diff --git a/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html b/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html index fd9ee62f06..f133714e1a 100644 --- a/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html +++ b/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html @@ -6,6 +6,45 @@ + +

Ghidra 9.0.2 Change History (April 2019)

+ +

Bugs

+
+ +
+ +

Security

+
+ +
+

Ghidra 9.0.1 Change History (March 2019)

New Features

diff --git a/Ghidra/Features/Base/data/file_extension_icons.xml b/Ghidra/Features/Base/data/file_extension_icons.xml index 7a3f125c86..9db71c2daf 100644 --- a/Ghidra/Features/Base/data/file_extension_icons.xml +++ b/Ghidra/Features/Base/data/file_extension_icons.xml @@ -22,7 +22,7 @@ - + diff --git a/Ghidra/Features/Base/ghidra_scripts/MultiInstructionMemReference.java b/Ghidra/Features/Base/ghidra_scripts/MultiInstructionMemReference.java index 8681e16449..70b4f86dfb 100644 --- a/Ghidra/Features/Base/ghidra_scripts/MultiInstructionMemReference.java +++ b/Ghidra/Features/Base/ghidra_scripts/MultiInstructionMemReference.java @@ -39,37 +39,59 @@ //@category Analysis import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; import ghidra.app.script.GhidraScript; -import ghidra.program.model.address.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressRange; +import ghidra.program.model.address.AddressRangeImpl; +import ghidra.program.model.address.AddressRangeIterator; +import ghidra.program.model.address.AddressSet; +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.address.AddressSpace; import ghidra.program.model.block.CodeBlock; import ghidra.program.model.block.PartitionCodeSubModel; -import ghidra.program.model.lang.*; +import ghidra.program.model.lang.OperandType; +import ghidra.program.model.lang.Register; +import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Instruction; +import ghidra.program.model.pcode.Varnode; import ghidra.program.model.symbol.RefType; +import ghidra.program.model.symbol.Reference; import ghidra.program.model.symbol.SourceType; -import ghidra.program.util.*; +import ghidra.program.util.ContextEvaluator; +import ghidra.program.util.ContextEvaluatorAdapter; +import ghidra.program.util.OperandFieldLocation; +import ghidra.program.util.SymbolicPropogator; +import ghidra.program.util.VarnodeContext; import ghidra.util.exception.CancelledException; -import ghidra.util.task.TaskMonitor; public class MultiInstructionMemReference extends GhidraScript { Address memReferenceLocation = null; private Address curInstrloc; - + private Object[] inputObjects; + private Object[] resultObjects; + private Register singleRegister; + private boolean registerInOut; + @Override public void run() throws Exception { long numInstructions = currentProgram.getListing().getNumInstructions(); monitor.initialize((int) (numInstructions)); monitor.setMessage("Multi-Instruction Reference Markup"); - int currentOpIndex = 0; + int currentOpIndex = -1; Address start = currentLocation.getAddress(); if ((currentSelection == null || currentSelection.isEmpty()) && currentLocation instanceof OperandFieldLocation) { - currentOpIndex = ((OperandFieldLocation) currentLocation).getOperandIndex(); + OperandFieldLocation operandLocation = (OperandFieldLocation) currentLocation; + currentOpIndex = operandLocation.getOperandIndex(); + int subOpIndex = operandLocation.getSubOperandIndex(); + singleRegister = getRegister(start, currentOpIndex, subOpIndex); } // set up the address set to restrict processing @@ -81,6 +103,34 @@ public class MultiInstructionMemReference extends GhidraScript { findMemRefAtOperand(currentOpIndex, refLocationsSet); } + /** + * Get the register at the location + * + * @param opIndex index into operands for instruction + * @param subOpIndex index into operands for an operand location + * + * @return register if there is one at the location + */ + private Register getRegister(Address addr, int opIndex, int subOpIndex) { + if (addr == null) { + return null; + } + + Instruction instr = currentProgram.getListing().getInstructionContaining(addr); + if (instr == null) { + return null; + } + + List defOpRep = instr.getDefaultOperandRepresentationList(opIndex); + if (subOpIndex >= 0 && subOpIndex < defOpRep.size()) { + Object obj = defOpRep.get(subOpIndex); + if (obj instanceof Register) { + return (Register) obj; + } + } + return instr.getRegister(opIndex); + } + @SuppressWarnings("unused") private boolean isSingleInstructions(AddressSet restrictedSet) { if (restrictedSet.isEmpty()) { @@ -106,53 +156,154 @@ public class MultiInstructionMemReference extends GhidraScript { // use context to fill out addresses on certain instructions ContextEvaluator eval = new ContextEvaluatorAdapter() { + @Override + public boolean evaluateContextBefore(VarnodeContext context, Instruction instr) { + // if the requested reference was on an input op-object, get context before exec + return checkContext(true, opIndex, context, instr); + } + @Override public boolean evaluateContext(VarnodeContext context, Instruction instr) { - // TODO: could look at instructions like LEA, that are an address to create a reference to something. + // if the requested reference was on an output op-object, get context after exec + return checkContext(false, opIndex, context, instr); + } + + + private boolean checkContext(boolean input, final int opIndex, VarnodeContext context, Instruction instr) { if (instr.getMinAddress().equals(curInstrloc)) { - if (checkInstructionMatch(opIndex, context, instr)) { + if (checkInstructionMatch(opIndex, input, context, instr)) { return true; } // if instruction is in delayslot, assume reference is good. if (instr.getDelaySlotDepth() > 0) { instr = instr.getNext(); - return checkInstructionMatch(opIndex, context, instr); + return checkInstructionMatch(opIndex, input, context, instr); } } return false; } + - private boolean checkInstructionMatch(final int opIdx, VarnodeContext context, + @Override + public boolean evaluateReference(VarnodeContext context, Instruction instr, int pcodeop, Address address, + int size, RefType refType) { + + return super.evaluateReference(context, instr, pcodeop, address, size, refType); + } + + + private boolean checkInstructionMatch(final int opIdx, boolean input, VarnodeContext context, Instruction instr) { - int firstIndex = opIdx; - if (instr.getRegister(firstIndex) == null) { - firstIndex = 0; - } - for (int index = firstIndex; index < instr.getNumOperands(); index++) { - Object[] opObjects = instr.getOpObjects(index); - for (int indexOpObj = 0; indexOpObj < opObjects.length; indexOpObj++) { - if (!(opObjects[indexOpObj] instanceof Register)) { - continue; + List list = Arrays.asList(input ? inputObjects : resultObjects); + + for (int index = opIdx; index < instr.getNumOperands(); index++) + { + if (getRefsForOperand(context, instr, list, index)) { + // register is both an in/out check if symbolic on out + if (registerInOut) { + break; } - Register reg = (Register) opObjects[indexOpObj]; - RegisterValue rval = context.getRegisterValue(reg); - if (rval == null) { - continue; - } - BigInteger uval = rval.getUnsignedValue(); - if (uval == null) { - continue; - } - long offset = uval.longValue(); - AddressSpace space = instr.getMinAddress().getAddressSpace(); - Address addr = space.getTruncatedAddress(offset, true); - - // assume that they want the reference, don't worry it isn't in memory - makeReference(instr, index, addr, monitor); - return false; - + return true; } } + if (addSymbolicRefs(input, context, instr, list)) { + return true; + } + return false; + } + + + /** + * Check the current operand for references based on input/outputs + * + * @param context - context holding values + * @param instr - instruction under consideration + * @param list - input/output lists + * @param opIndex - index of operand to check + * + * @return true if a reference was found + */ + private boolean getRefsForOperand(VarnodeContext context, Instruction instr, List list, int opIndex) { + Object[] opObjects = instr.getOpObjects(opIndex); + for (int indexOpObj = 0; indexOpObj < opObjects.length; indexOpObj++) { + if (!(opObjects[indexOpObj] instanceof Register)) { + continue; + } + Register reg = (Register) opObjects[indexOpObj]; + + // if operand has a single register and this isn't it + if (singleRegister != null && !reg.equals(singleRegister)) { + continue; + } + + // check that the register is on the correct input/output list + if (!list.contains(reg)) { + continue; + } + RegisterValue rval = context.getRegisterValue(reg); + if (rval == null) { + continue; + } + BigInteger uval = rval.getUnsignedValue(); + if (uval == null) { + continue; + } + long offset = uval.longValue(); + + AddressSpace space = instr.getMinAddress().getAddressSpace(); + Address addr = space.getTruncatedAddress(offset, true); + + // assume that they want the reference, don't worry it isn't in memory + makeReference(instr, opIndex, addr); + return true; + } + return false; + } + + private boolean addSymbolicRefs(boolean input, VarnodeContext context, Instruction instr, List list) { + // get the value of the single register to see if this is the value desired + if (singleRegister == null) { + return false; + } + // check that the register is on the correct input/output list + if (!list.contains(singleRegister)) { + return false; + } + Varnode registerVarnodeValue = context.getRegisterVarnodeValue(singleRegister); + if (!context.isSymbol(registerVarnodeValue) && !registerVarnodeValue.isRegister()) { + return false; + } + Address symAddr = registerVarnodeValue.getAddress(); + if (symAddr == context.BAD_ADDRESS) { + return false; + } + + String valStr = ""; + if (registerVarnodeValue.isRegister()) { + valStr = context.getRegister(registerVarnodeValue).toString(); + } else { + // is an offset from a space + String name = symAddr.getAddressSpace().getName(); + BigInteger offset = symAddr.getOffsetAsBigInteger(); + valStr = name + " + 0x" + offset.toString(16); + } + Address lastSetLocation = context.getLastSetLocation(singleRegister, null); + + + String comment = instr.getComment(Instruction.EOL_COMMENT); + if (comment == null) { + comment = ""; + } + + String inoutChar = (input ? " " : "\'"); + String lastStr = (lastSetLocation != null ? " @" + lastSetLocation : ""); + + String markup = singleRegister+inoutChar+"= "+ valStr + lastStr; + if (comment.replace('\'',' ').contains(markup.replace('\'',' '))) { + return false; + } + comment = (comment.trim().length()==0 ? markup : comment + "\n" + markup); + instr.setComment(Instruction.EOL_COMMENT, comment); return false; } @@ -188,8 +339,14 @@ public class MultiInstructionMemReference extends GhidraScript { } } - // if the instruction attempting to markup is in the delayslot, backup an instruction Instruction instr = currentProgram.getListing().getInstructionAt(curInstrloc); + if (instr != null) { + inputObjects = instr.getInputObjects(); + resultObjects = instr.getResultObjects(); + registerInOut = checkRegisterInOut(singleRegister, inputObjects, resultObjects); + } + + // if the instruction attempting to markup is in the delayslot, backup an instruction if (instr != null && instr.isInDelaySlot()) { instr = instr.getPrevious(); if (instr != null) { @@ -209,16 +366,24 @@ public class MultiInstructionMemReference extends GhidraScript { } } - /** - * @param instruction - * @param space - * @param scalar - * @param nextInstr - * @param addend - * @param taskMonitor + private boolean checkRegisterInOut(Register reg, Object[] in, Object[] out) { + if (reg == null || in == null || out == null) { + return false; + } + + List inList = Arrays.asList(in); + List outList = Arrays.asList(out); + + return inList.contains(reg) && outList.contains(reg); + } + + /** Make the reference on the instruction at the correct location. + * + * @param instruction to receive reference + * @param space reference created in this space + * @param scalar used as offset into address space */ - private void makeReference(Instruction instruction, int opIndex, Address addr, - TaskMonitor taskMonitor) { + private void makeReference(Instruction instruction, int opIndex, Address addr) { if (instruction.getPrototype().hasDelaySlots()) { instruction = instruction.getNext(); if (instruction == null) { @@ -238,6 +403,13 @@ public class MultiInstructionMemReference extends GhidraScript { if (opIndex == -1) { opIndex = instruction.getNumOperands() - 1; } + + // check if it already has the reference + Reference[] referencesFrom = instruction.getReferencesFrom(); + boolean hasRef = Arrays.stream(referencesFrom).anyMatch(p -> p.getToAddress().equals(addr)); + if (hasRef) { + return; + } if (opIndex == -1) { instruction.addMnemonicReference(addr, RefType.DATA, SourceType.ANALYSIS); diff --git a/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/exporter.htm b/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/exporter.htm index 27f1bb5d34..3c35967519 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/exporter.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/exporter.htm @@ -306,6 +306,12 @@
  • Address Space - Specifies which address space to export as Intel Hex format only supports one address space. This option will be intialized to the "default" address space.
  • +
  • Record Size - Specifies the size (in bytes) of each record in the + output file. The default 16.
  • +
  • Align To Record Size - If checked, this will ensure that only records matching + the record size will be output. eg: if you set the record size to 16 but there are + 18 bytes selected, you will see only one line of 16 bytes in the output; the remaining + 2 bytes will be dropped.
  • diff --git a/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/images/Intel_Hex_Options.png b/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/images/Intel_Hex_Options.png index 31e0df87d2..614e2f37d3 100644 Binary files a/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/images/Intel_Hex_Options.png and b/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/images/Intel_Hex_Options.png differ diff --git a/Ghidra/Features/Base/src/main/java/foundation/FoundationInitializer.java b/Ghidra/Features/Base/src/main/java/foundation/FoundationInitializer.java index 40a9a6b1ea..2634a143fd 100644 --- a/Ghidra/Features/Base/src/main/java/foundation/FoundationInitializer.java +++ b/Ghidra/Features/Base/src/main/java/foundation/FoundationInitializer.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,21 +15,29 @@ */ package foundation; -import ghidra.app.factory.*; -import ghidra.app.util.*; -import ghidra.framework.*; -import ghidra.framework.data.*; -import ghidra.framework.main.datatree.*; +import ghidra.app.factory.GhidraToolStateFactory; +import ghidra.app.util.GhidraFileOpenDataFlavorHandlerService; +import ghidra.framework.ModuleInitializer; +import ghidra.framework.PluggableServiceRegistry; +import ghidra.framework.data.ToolStateFactory; +import ghidra.framework.main.datatree.GhidraDataFlavorHandlerService; import ghidra.program.database.*; public class FoundationInitializer implements ModuleInitializer { - public void run() { - PluggableServiceRegistry.registerPluggableService( ToolStateFactory.class, new GhidraToolStateFactory() ); - PluggableServiceRegistry.registerPluggableService( DataFlavorHandlerService.class, new GhidraDataFlavorHandlerService() ); - PluggableServiceRegistry.registerPluggableService( FileOpenDataFlavorHandlerService.class, new GhidraFileOpenDataFlavorHandlerService() ); - PluggableServiceRegistry.registerPluggableService( DataTypeArchiveMergeManagerFactory.class, new GhidraDataTypeArchiveMergeManagerFactory() ); - PluggableServiceRegistry.registerPluggableService( ProgramMultiUserMergeManagerFactory.class, new GhidraProgramMultiUserMergeManagerFactory() ); - } + @Override + public void run() { + PluggableServiceRegistry.registerPluggableService(ToolStateFactory.class, + new GhidraToolStateFactory()); + PluggableServiceRegistry.registerPluggableService(GhidraDataFlavorHandlerService.class, + new GhidraDataFlavorHandlerService()); + PluggableServiceRegistry.registerPluggableService( + GhidraFileOpenDataFlavorHandlerService.class, + new GhidraFileOpenDataFlavorHandlerService()); + PluggableServiceRegistry.registerPluggableService(DataTypeArchiveMergeManagerFactory.class, + new GhidraDataTypeArchiveMergeManagerFactory()); + PluggableServiceRegistry.registerPluggableService(ProgramMultiUserMergeManagerFactory.class, + new GhidraProgramMultiUserMergeManagerFactory()); + } @Override public String getName() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java index 88206fca8d..b8368f46ad 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationAnalyzer.java @@ -67,10 +67,16 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { protected static final int MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE = 4; protected static final String MINSPECULATIVEREFADDRESS_OPTION_NAME = - "Min speculative reference"; + "Speculative reference min"; protected static final String MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION = "Minimum speculative reference address for offsets and parameters"; protected static final int MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE = 1024; + + protected static final String MAXSPECULATIVEREFADDRESS_OPTION_NAME = + "Speculative reference max"; + protected static final String MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION = + "Maxmimum speculative reference address offset from the end of memory for offsets and parameters"; + protected static final int MAXSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE = 256; protected final static int NOTIFICATION_INTERVAL = 100; @@ -80,6 +86,7 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { protected int maxThreadCount = MAXTHREADCOUNT_OPTION_DEFAULT_VALUE; protected long minStoreLoadRefAddress = MINKNOWNREFADDRESS_OPTION_DEFAULT_VALUE; protected long minSpeculativeRefAddress = MINSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE; + protected long maxSpeculativeRefAddress = MAXSPECULATIVEREFADDRESS_OPTION_DEFAULT_VALUE; protected boolean followConditional = false; @@ -391,7 +398,7 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { throws CancelledException { ContextEvaluator eval = new ConstantPropagationContextEvaluator(trustWriteMemOption, - minStoreLoadRefAddress, minSpeculativeRefAddress); + minStoreLoadRefAddress, minSpeculativeRefAddress, maxSpeculativeRefAddress); return symEval.flowConstants(flowStart, flowSet, eval, true, monitor); } @@ -461,9 +468,13 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { MINKNOWNREFADDRESS_OPTION_DESCRIPTION); long size = program.getAddressFactory().getDefaultAddressSpace().getSize(); - minSpeculativeRefAddress = size * 8; + minSpeculativeRefAddress = size * 16; options.registerOption(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress, null, MINSPECULATIVEREFADDRESS_OPTION_DESCRIPTION); + + maxSpeculativeRefAddress = size * 8; + options.registerOption(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress, null, + MAXSPECULATIVEREFADDRESS_OPTION_DESCRIPTION); } @Override @@ -479,6 +490,8 @@ public class ConstantPropagationAnalyzer extends AbstractAnalyzer { options.getLong(MINKNOWNREFADDRESS_OPTION_NAME, minStoreLoadRefAddress); minSpeculativeRefAddress = options.getLong(MINSPECULATIVEREFADDRESS_OPTION_NAME, minSpeculativeRefAddress); + maxSpeculativeRefAddress = + options.getLong(MAXSPECULATIVEREFADDRESS_OPTION_NAME, maxSpeculativeRefAddress); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.java index 08e4ac1315..acb8c08048 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ConstantPropagationContextEvaluator.java @@ -42,7 +42,9 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter protected AddressSet destSet = new AddressSet(); private boolean trustMemoryWrite = false; private long minStoreLoadOffset = 4; - private long minSpeculativeOffset = 1024; + private long minSpeculativeOffset = 1024; // from the beginning of memory + private long maxSpeculativeOffset = 256; // from the end of memory + public ConstantPropagationContextEvaluator() { } @@ -55,10 +57,10 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter } public ConstantPropagationContextEvaluator(boolean trustWriteMemOption, - long minStoreLoadRefAddress, long minSpeculativeRefAddress) { + long minStoreLoadRefAddress, long minSpeculativeRefAddress, long maxSpeculativeRefAddress) { this(trustWriteMemOption); this.minStoreLoadOffset = minStoreLoadRefAddress; - this.minSpeculativeOffset = minSpeculativeRefAddress; + this.maxSpeculativeOffset = maxSpeculativeRefAddress; } /** @@ -85,7 +87,7 @@ public class ConstantPropagationContextEvaluator extends ContextEvaluatorAdapter long wordOffset = constant.getOffset(); if (((wordOffset >= 0 && wordOffset < minSpeculativeOffset) || - (Math.abs(maxAddrOffset - wordOffset) < minSpeculativeOffset)) && + (Math.abs(maxAddrOffset - wordOffset) < maxSpeculativeOffset)) && !space.isExternalSpace()) { return null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java index 0a30be7cb2..a8d486d338 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/archive/ArchivePlugin.java @@ -93,7 +93,7 @@ public class ArchivePlugin extends Plugin implements FrontEndOnly, ProjectListen private volatile boolean isArchiving; private volatile boolean isRestoring; private TaskListener archivingListener; - private TaskListener restoringListner; + private TaskListener restoringListener; ////////////////////////////////////////////////////////////////// @@ -282,7 +282,7 @@ public class ArchivePlugin extends Plugin implements FrontEndOnly, ProjectListen isRestoring = true; - restoringListner = new TaskListener() { + restoringListener = new TaskListener() { @Override public void taskCompleted(Task task) { isRestoring = false; @@ -295,7 +295,7 @@ public class ArchivePlugin extends Plugin implements FrontEndOnly, ProjectListen }; Task task = new RestoreTask(lastRestoreLocator, archiveJar, this); - task.addTaskListener(restoringListner); + task.addTaskListener(restoringListener); new TaskLauncher(task, tool.getToolFrame()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesActionContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesActionContext.java index 40aed341b9..4b8ebb9d45 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesActionContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/DataTypesActionContext.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +15,12 @@ */ package ghidra.app.plugin.core.datamgr; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.tree.TreePath; + +import docking.widgets.tree.GTreeNode; import ghidra.app.context.ProgramActionContext; import ghidra.app.plugin.core.datamgr.archive.ProjectArchive; import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree; @@ -24,13 +29,6 @@ import ghidra.framework.main.datatable.DomainFileProvider; import ghidra.framework.model.DomainFile; import ghidra.program.model.listing.Program; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.tree.TreePath; - -import docking.widgets.tree.GTreeNode; - public class DataTypesActionContext extends ProgramActionContext implements DomainFileProvider { private final GTreeNode clickedNode; private final boolean isToolbarAction; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/MyProgramChangesDisplayPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/MyProgramChangesDisplayPlugin.java index fa44fde9b8..897fa89840 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/MyProgramChangesDisplayPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/misc/MyProgramChangesDisplayPlugin.java @@ -242,6 +242,10 @@ public class MyProgramChangesDisplayPlugin extends ProgramPlugin implements Doma public void dispose() { worker.dispose(); + if (currentProgram != null) { + currentProgram.removeTransactionListener(transactionListener); + currentProgram.removeListener(this); + } tool.getProject().getProjectData().removeDomainFolderChangeListener(folderListener); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/GhidraFileOpenDataFlavorHandlerService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/GhidraFileOpenDataFlavorHandlerService.java index 938be9843d..5302137db7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/GhidraFileOpenDataFlavorHandlerService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/GhidraFileOpenDataFlavorHandlerService.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +15,13 @@ */ package ghidra.app.util; -import ghidra.framework.main.datatree.*; - import java.awt.datatransfer.DataFlavor; -public class GhidraFileOpenDataFlavorHandlerService extends FileOpenDataFlavorHandlerService { +import ghidra.framework.main.datatree.*; - @Override - protected void doRegisterDataFlavorHandlers() { +public class GhidraFileOpenDataFlavorHandlerService { + + public GhidraFileOpenDataFlavorHandlerService() { try { DataFlavor linuxFileUrlFlavor = @@ -34,15 +32,15 @@ public class GhidraFileOpenDataFlavorHandlerService extends FileOpenDataFlavorHa // should never happen as it is using java.lang.String } - LocalTreeNodeFlavorHandler localHandler = new LocalTreeNodeFlavorHandler(); + LocalTreeNodeHandler localHandler = new LocalTreeNodeHandler(); FileOpenDropHandler.addDataFlavorHandler(DataTreeDragNDropHandler.localDomainFileFlavor, localHandler); - FileOpenDropHandler.addDataFlavorHandler(VersionInfoTransferable.localVersionInfoFlavor, + FileOpenDropHandler.addDataFlavorHandler(DataTreeDragNDropHandler.localDomainFileTreeFlavor, localHandler); - FileOpenDropHandler.addDataFlavorHandler(DataFlavor.javaFileListFlavor, - new JavaFileListFlavorHandler()); - FileOpenDropHandler.addDataFlavorHandler( - DataTreeDragNDropHandler.localDomainFileTreeFlavor, localHandler); + FileOpenDropHandler.addDataFlavorHandler(VersionInfoTransferable.localVersionInfoFlavor, + new LocalVersionInfoHandler()); + FileOpenDropHandler.addDataFlavorHandler(DataFlavor.javaFileListFlavor, + new JavaFileListHandler()); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/JavaFileListFlavorHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/JavaFileListFlavorHandler.java deleted file mode 100644 index 3bf09ff2e5..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/JavaFileListFlavorHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -/* ### - * 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 ghidra.app.util; - -import java.awt.datatransfer.DataFlavor; -import java.awt.dnd.DropTargetDropEvent; -import java.io.File; -import java.util.List; - -import ghidra.app.services.FileImporterService; -import ghidra.framework.model.DomainFolder; -import ghidra.framework.plugintool.PluginTool; -import util.CollectionUtils; - -final class JavaFileListFlavorHandler implements FileOpenDataFlavorHandler { - @Override - public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f) { - List files = CollectionUtils.asList((List) obj, File.class); - - FileImporterService im = tool.getService(FileImporterService.class); - if (im == null) { - tool.setStatusInfo("ERROR: Could not get importer service."); - return; - } - - DomainFolder rootFolder = tool.getProject().getProjectData().getRootFolder(); - - if (files.size() == 1 && files.get(0).isFile()) { - im.importFile(rootFolder, files.get(0)); - } - else { - im.importFiles(rootFolder, files); - } - } -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/Option.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/Option.java index afe63dcd5f..e5262f5181 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/Option.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/Option.java @@ -96,6 +96,15 @@ public class Option { this.listener = listener; } + /** + * Override if you want to provide a custom widget for selecting your + * options. + *

    + * Important! If you override this you MUST also override the {@link #copy()} + * method so it returns a new instance of your custom editor. + * + * @return the custom editor + */ public Component getCustomEditorComponent() { return null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/Compare.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/Compare.java index 58ba286399..4b2fb28cb5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/Compare.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/Compare.java @@ -25,17 +25,17 @@ import ghidra.util.Msg; public class Compare { public static void compare(ArrayList expectedList, File actualFile) throws Exception { int index = 0; - BufferedReader reader = new BufferedReader(new FileReader(actualFile)); - + boolean hasFailure = false; - try { + try (BufferedReader reader = new BufferedReader(new FileReader(actualFile))) { int excess = 0; while (true) { String actualLine = reader.readLine(); if (actualLine == null) { break; } + if (index >= expectedList.size()) { ++excess; continue; @@ -73,8 +73,5 @@ public class Compare { Assert.fail("One or more failures--see output for data"); } } - finally { - reader.close(); - } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/IntelHexExporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/IntelHexExporter.java index 29242fff3b..47ba38d9ef 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/IntelHexExporter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/IntelHexExporter.java @@ -15,10 +15,15 @@ */ package ghidra.app.util.exporter; +import java.awt.BorderLayout; +import java.awt.Component; import java.io.*; import java.util.ArrayList; import java.util.List; +import javax.swing.*; + +import docking.widgets.textfield.HintTextField; import ghidra.app.util.*; import ghidra.app.util.opinion.IntelHexRecord; import ghidra.app.util.opinion.IntelHexRecordWriter; @@ -29,18 +34,55 @@ import ghidra.program.model.mem.*; import ghidra.util.HelpLocation; import ghidra.util.task.TaskMonitor; +/** + * Exports the current program (or program selection) as bytes in Intel Hex format. + *

    + * The output defaults to lines of 16-bytes but this is configurable using the + * {@link #recordSizeOption} attribute. This allows users to select any record size + * up to the max of 0xFF. Users may also choose to Drop Extra Bytes, which will + * cause only lines that match the max record size to be printed; any other + * bytes will be dropped. If this option is not set, every byte will be represented in the output. + */ public class IntelHexExporter extends Exporter { - protected final static int MAX_BYTES_PER_LINE = 0x00000010; - - protected Option option; + /** Option allowing the user to select the address space */ + protected Option addressSpaceOption; + + /** Option allowing the user to select the number of bytes in each line of output */ + protected RecordSizeOption recordSizeOption; + + private static final int DEFAULT_RECORD_SIZE = 0x10; + /** - * Constructs a new Intel Hex exporter. + * Constructs a new Intel Hex exporter. This will use a record size of 16 (the default) + * and will export ALL bytes in the program or selection (even if the total length + * is not a multiple of 16. */ public IntelHexExporter() { this("Intel Hex", "hex", new HelpLocation("ExporterPlugin", "intel_hex")); } - + + /** + * Constructs a new Intel Hex exporter with a custom record size. + * + * @param recordSize the record size to use when writing to the output file + * @param dropBytes if true, bytes at the end of the file that don't match the specified + * record size will be dropped + */ + public IntelHexExporter(int recordSize, boolean dropBytes) { + this("Intel Hex", "hex", new HelpLocation("ExporterPlugin", "intel_hex")); + recordSizeOption = new RecordSizeOption("Record Size", Integer.class); + recordSizeOption.setRecordSize(recordSize); + recordSizeOption.setDropBytes(dropBytes); + } + + /** + * Constructor + * + * @param name the name of the exporter + * @param extension the extension to use for the output file + * @param help location of Ghidra help + */ protected IntelHexExporter(String name, String extension, HelpLocation help) { super(name, extension, help); } @@ -55,16 +97,49 @@ public class IntelHexExporter extends Exporter { } Program program = (Program) domainObject; - option = new Option("Address Space", program.getAddressFactory().getDefaultAddressSpace()); + addressSpaceOption = + new Option("Address Space", program.getAddressFactory().getDefaultAddressSpace()); + + if (recordSizeOption == null) { + recordSizeOption = new RecordSizeOption("Record Size", Integer.class); + } + + optionsList.add(addressSpaceOption); + optionsList.add(recordSizeOption); - optionsList.add(option); return optionsList; } @Override public void setOptions(List

    + * Input may be specified in either decimal or hex. + */ + private class BoundedIntegerVerifier extends InputVerifier { + + @Override + public boolean verify(JComponent input) { + HintTextField field = (HintTextField) input; + String text = field.getText(); + + int val; + try { + val = Integer.decode(text); + } + catch (NumberFormatException e) { + return false; + } + + return val <= 0xFF && val >= 0; } } @@ -84,33 +159,31 @@ public class IntelHexExporter extends Exporter { return false; } - if (option == null) { + if (addressSpaceOption == null || recordSizeOption == null) { getOptions(() -> program); } - PrintWriter writer = new PrintWriter(new FileOutputStream(file)); + try (PrintWriter writer = new PrintWriter(new FileOutputStream(file))) { - Memory memory = program.getMemory(); + Memory memory = program.getMemory(); - if (addrSet == null) { - addrSet = memory; - } - - try { - List records = dumpMemory(program, memory, addrSet, monitor); - for (IntelHexRecord record : records) { - writer.println(record.format()); + if (addrSet == null) { + addrSet = memory; } - } - catch (MemoryAccessException e) { - throw new ExporterException(e); - } - finally { - // Close the PrintWriter - // - writer.close(); - option = null; + try { + List records = dumpMemory(program, memory, addrSet, monitor); + for (IntelHexRecord record : records) { + writer.println(record.format()); + } + } + catch (MemoryAccessException e) { + throw new ExporterException(e); + } + finally { + addressSpaceOption = null; + recordSizeOption = null; + } } return true; @@ -118,15 +191,19 @@ public class IntelHexExporter extends Exporter { protected List dumpMemory(Program program, Memory memory, AddressSetView addrSetView, TaskMonitor monitor) throws MemoryAccessException { - IntelHexRecordWriter writer = new IntelHexRecordWriter(MAX_BYTES_PER_LINE); + + int size = (int) recordSizeOption.getValue(); + boolean dropBytes = recordSizeOption.dropExtraBytes(); + + IntelHexRecordWriter writer = new IntelHexRecordWriter(size, dropBytes); AddressSet set = new AddressSet(addrSetView); MemoryBlock[] blocks = memory.getBlocks(); - for (int i = 0; i < blocks.length; ++i) { - if (!blocks[i].isInitialized() || - blocks[i].getStart().getAddressSpace() != option.getValue()) { - set.delete(new AddressRangeImpl(blocks[i].getStart(), blocks[i].getEnd())); + for (MemoryBlock block : blocks) { + if (!block.isInitialized() || + block.getStart().getAddressSpace() != addressSpaceOption.getValue()) { + set.delete(new AddressRangeImpl(block.getStart(), block.getEnd())); } } @@ -148,4 +225,113 @@ public class IntelHexExporter extends Exporter { } return writer.finish(entryPoint); } + + /** + * Option for exporting Intel Hex records that allows users to specify a record size for the + * output. Users may also optionally select the Drop Extra Bytes option that + * will cause only those records that match the maximum size to be output to the file. + * + * @see RecordSizeComponent + */ + private class RecordSizeOption extends Option { + + private final RecordSizeComponent comp = new RecordSizeComponent(DEFAULT_RECORD_SIZE); + + public RecordSizeOption(String name, Class valueClass) { + super(name, valueClass); + } + + public RecordSizeOption(String name, Class valueClass, Object value, String arg, + String group) { + super(name, valueClass, value, arg, group); + } + + @Override + public Component getCustomEditorComponent() { + return comp; + } + + @Override + public Option copy() { + return new RecordSizeOption(getName(), getValueClass(), getValue(), getArg(), + getGroup()); + } + + @Override + public Object getValue() { + return comp.getValue(); + } + + @Override + public Class getValueClass() { + return Integer.class; + } + + public boolean dropExtraBytes() { + return comp.dropExtraBytes(); + } + + public void setRecordSize(int recordSize) { + comp.setRecordSize(recordSize); + } + + public void setDropBytes(boolean dropBytes) { + comp.setDropBytes(dropBytes); + } + } + + /** + * Component that displays two widgets for setting export options: + * + *

      + *
    • input: a {@link HintTextField} for entering numeric digits; these + * represent the record size for each line of output
    • + *
    • dropCb: a {@link JCheckBox} for specifying a setting that enforces that every line in + * the output matches the specified record size
    • + *
    + * + * Note: If the Drop Extra Bytes option is set, any bytes that are left over + * after outputting all lines that match the record size will be omitted from the output. + */ + private class RecordSizeComponent extends JPanel { + + private HintTextField input; + private JCheckBox dropCb; + + public RecordSizeComponent(int recordSize) { + setLayout(new BorderLayout()); + + input = new HintTextField(Integer.toString(recordSize), false, new BoundedIntegerVerifier()); + dropCb = new JCheckBox("Align To Record Size"); + + input.setText(Integer.toString(recordSize)); + + add(input, BorderLayout.CENTER); + add(dropCb, BorderLayout.EAST); + } + + public int getValue() { + String val = input.getText(); + if (!input.isFieldValid()) { + + // If the user clears the input field, revert to the default + // record size (16). + return DEFAULT_RECORD_SIZE; + } + + return Integer.valueOf(val); + } + + public boolean dropExtraBytes() { + return dropCb.isSelected(); + } + + public void setRecordSize(int recordSize) { + input.setText(Integer.toString(recordSize)); + } + + public void setDropBytes(boolean dropBytes) { + dropCb.setSelected(dropBytes); + } + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexRecordWriter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexRecordWriter.java index 623417a12a..16d21698c1 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexRecordWriter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/IntelHexRecordWriter.java @@ -20,21 +20,31 @@ import java.util.*; import ghidra.program.model.address.*; public class IntelHexRecordWriter { + private final int maxBytesPerLine; + private final boolean dropExtraBytes; private Address startAddress = null; private Long oldSegment = null; - private ArrayList bytes = new ArrayList(); + private ArrayList bytes = new ArrayList<>(); private Boolean isSegmented = null; - private ArrayList results = new ArrayList(); + private ArrayList results = new ArrayList<>(); private boolean done = false; - public IntelHexRecordWriter(int maxBytesPerLine) { + /** + * Constructor + * + * @param maxBytesPerLine the maximum number of bytes to write per line in the hex output + * @param dropExtraBytes if true, only lines matching {@link #maxBytesPerLine} will be output; + * remaining bytes will be left out + */ + public IntelHexRecordWriter(int maxBytesPerLine, boolean dropExtraBytes) { if (maxBytesPerLine > IntelHexRecord.MAX_RECORD_LENGTH) { throw new IllegalArgumentException("maxBytesPerLine > IntelHexRecord.MAX_RECORD_LENGTH"); } this.maxBytesPerLine = maxBytesPerLine; + this.dropExtraBytes = dropExtraBytes; } public void addByte(Address address, byte b) { @@ -117,6 +127,14 @@ public class IntelHexRecordWriter { } public List finish(Address entryPoint) { + + // Before finalizing things, write out any remaining bytes that haven't yet been written, if + // the user has specified to do so via the drop extra bytes option (false = + // write out everything). + if (bytes.size() > 0 && !dropExtraBytes) { + emitData(); + } + if (entryPoint != null && isSegmented != null) { final long offset = entryPoint.getOffset(); byte[] data = new byte[4]; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FieldHighlightFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FieldHighlightFactory.java index c46721d71e..7f340dc38f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FieldHighlightFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FieldHighlightFactory.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +15,7 @@ */ package ghidra.app.util.viewer.field; +import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.support.Highlight; import docking.widgets.fieldpanel.support.HighlightFactory; import ghidra.app.util.HighlightProvider; @@ -30,26 +30,22 @@ public class FieldHighlightFactory implements HighlightFactory { private HighlightProvider provider; private Class fieldFactoryClass; private Object obj; - + /** * Constructs a new FieldHighlightFactory. * @param provider the HighlightProvider that will actually compute the highlights. * @param fieldFactoryClass the class of the field factory that generated the field to be rendered. * @param obj the object that holds the information that will be rendered (usually a code unit) */ - public FieldHighlightFactory(HighlightProvider provider, Class fieldFactoryClass, Object obj) { + public FieldHighlightFactory(HighlightProvider provider, + Class fieldFactoryClass, Object obj) { this.provider = provider; this.fieldFactoryClass = fieldFactoryClass; this.obj = obj; } - - /** - * Returns the highlights for the given text. - * @param text the text to be considered for highlighting. - * @return an array of highlights to be rendered. - */ - public Highlight[] getHighlights(String text, int cursorTextOffset) { + + @Override + public Highlight[] getHighlights(Field field, String text, int cursorTextOffset) { return provider.getHighlights(text, obj, fieldFactoryClass, cursorTextOffset); } - } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/OptionsGui.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/OptionsGui.java index 0ef35c6d47..4d58561dec 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/OptionsGui.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/options/OptionsGui.java @@ -51,7 +51,8 @@ public class OptionsGui extends JPanel { private static final Color DARK_ORANGE = new Color(255, 128, 0); private static final Color DARK_RED = new Color(130, 0, 75); private static final Highlight[] NO_HIGHLIGHTS = new Highlight[0]; - private static final HighlightFactory hlFactory = (text, cursorTextOffset) -> NO_HIGHLIGHTS; + private static final HighlightFactory hlFactory = + (field, text, cursorTextOffset) -> NO_HIGHLIGHTS; public static final ScreenElement COMMENT_AUTO = new ScreenElement("Comment, Automatic", Color.LIGHT_GRAY); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/DataTreeDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/DataTreeDialog.java index cee3dd427a..526202aadd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/DataTreeDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/DataTreeDialog.java @@ -26,6 +26,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import docking.*; +import docking.event.mouse.GMouseListenerAdapter; import docking.widgets.tree.support.GTreeSelectionEvent; import docking.widgets.tree.support.GTreeSelectionListener; import ghidra.framework.main.datatree.ClearCutAction; @@ -40,7 +41,7 @@ import ghidra.util.layout.PairLayout; * Dialog to open or save domain data items to a new location or name. */ public class DataTreeDialog extends DialogComponentProvider -implements GTreeSelectionListener, ActionListener { + implements GTreeSelectionListener, ActionListener { /** * Dialog type for opening domain data files. @@ -540,10 +541,11 @@ implements GTreeSelectionListener, ActionListener { protected void addTreeListeners() { if (type == OPEN) { - treePanel.addTreeMouseListener(new MouseAdapter() { + + treePanel.addTreeMouseListener(new GMouseListenerAdapter() { @Override - public void mousePressed(MouseEvent e) { - if (e.getClickCount() == 2 && okButton.isEnabled()) { + public void doubleClickTriggered(MouseEvent e) { + if (okButton.isEnabled()) { okCallback(); } } @@ -671,7 +673,7 @@ implements GTreeSelectionListener, ActionListener { // populate the combo box DefaultComboBoxModel model = - (DefaultComboBoxModel) projectComboBox.getModel(); + (DefaultComboBoxModel) projectComboBox.getModel(); model.removeAllElements(); Set map = new HashSet<>(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/GhidraDataFlavorHandlerService.java b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/GhidraDataFlavorHandlerService.java index 45967e040a..c17fe17662 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/GhidraDataFlavorHandlerService.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/GhidraDataFlavorHandlerService.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +17,10 @@ package ghidra.framework.main.datatree; import java.awt.datatransfer.DataFlavor; -public class GhidraDataFlavorHandlerService extends DataFlavorHandlerService { - @Override - protected void doRegisterDataFlavorHandlers() { +public class GhidraDataFlavorHandlerService { + + public GhidraDataFlavorHandlerService() { + try { DataFlavor linuxFileUrlFlavor = new DataFlavor("application/x-java-serialized-object;class=java.lang.String"); @@ -31,15 +31,12 @@ public class GhidraDataFlavorHandlerService extends DataFlavorHandlerService { // should never happen as it is using java.lang.String } - final LocalTreeNodeHandler localTreeNodeHandler = new LocalTreeNodeHandler(); + LocalTreeNodeHandler localNodeHandler = new LocalTreeNodeHandler(); DataTreeDragNDropHandler.addActiveDataFlavorHandler( - DataTreeDragNDropHandler.localDomainFileTreeFlavor, localTreeNodeHandler); + DataTreeDragNDropHandler.localDomainFileTreeFlavor, localNodeHandler); DataTreeDragNDropHandler.addActiveDataFlavorHandler(DataFlavor.javaFileListFlavor, new JavaFileListHandler()); DataTreeDragNDropHandler.addActiveDataFlavorHandler( VersionInfoTransferable.localVersionInfoFlavor, new LocalVersionInfoHandler()); - - DataTreeDragNDropHandler.addInactiveDataFlavorHandler( - DataTreeDragNDropHandler.localDomainFileTreeFlavor, localTreeNodeHandler); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/JavaFileListHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/JavaFileListHandler.java index 69c8bb74a5..cf3c03d8a8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/JavaFileListHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/JavaFileListHandler.java @@ -19,13 +19,15 @@ package ghidra.framework.main.datatree; import java.awt.datatransfer.DataFlavor; +import java.awt.dnd.DropTargetDropEvent; import java.io.File; import java.util.List; import docking.widgets.tree.GTreeNode; import ghidra.app.services.FileImporterService; -import ghidra.framework.main.FrontEndTool; +import ghidra.app.util.FileOpenDataFlavorHandler; import ghidra.framework.model.DomainFolder; +import ghidra.framework.plugintool.PluginTool; import ghidra.util.Msg; import util.CollectionUtils; @@ -33,24 +35,43 @@ import util.CollectionUtils; * A drag-and-drop handler for trees that is specific to List<File>. (see * {@link DataFlavor#javaFileListFlavor}). */ -final class JavaFileListHandler implements DataFlavorHandler { - @Override - public void handle(FrontEndTool tool, DataTree dataTree, GTreeNode destinationNode, - Object transferData, int dropAction) { - DomainFolder folder = getDomainFolder(destinationNode); +public final class JavaFileListHandler implements DataTreeFlavorHandler, FileOpenDataFlavorHandler { - FileImporterService im = tool.getService(FileImporterService.class); - if (im == null) { - Msg.showError(this, dataTree, "Could Not Import", "Could not find importer service"); + @Override + public void handle(PluginTool tool, Object transferData, DropTargetDropEvent e, DataFlavor f) { + + FileImporterService importer = tool.getService(FileImporterService.class); + if (importer == null) { + Msg.showError(this, null, "Could Not Import", "Could not find Importer Service"); return; } - List fileList = CollectionUtils.asList((List) transferData, File.class); + DomainFolder folder = tool.getProject().getProjectData().getRootFolder(); + doImport(importer, folder, transferData); + } + + @Override + public void handle(PluginTool tool, DataTree dataTree, GTreeNode destinationNode, + Object transferData, int dropAction) { + + FileImporterService importer = tool.getService(FileImporterService.class); + if (importer == null) { + Msg.showError(this, dataTree, "Could Not Import", "Could not find Importer Service"); + return; + } + + DomainFolder folder = getDomainFolder(destinationNode); + doImport(importer, folder, transferData); + } + + private void doImport(FileImporterService importer, DomainFolder folder, Object files) { + + List fileList = CollectionUtils.asList((List) files, File.class); if (fileList.size() == 1 && fileList.get(0).isFile()) { - im.importFile(folder, fileList.get(0)); + importer.importFile(folder, fileList.get(0)); } else { - im.importFiles(folder, fileList); + importer.importFiles(folder, fileList); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/LinuxFileUrlHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/LinuxFileUrlHandler.java index 9c6f1c115b..16a7e690ef 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/LinuxFileUrlHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/framework/main/datatree/LinuxFileUrlHandler.java @@ -27,7 +27,6 @@ import java.util.function.Function; import docking.widgets.tree.GTreeNode; import ghidra.app.services.FileImporterService; import ghidra.app.util.FileOpenDataFlavorHandler; -import ghidra.framework.main.FrontEndTool; import ghidra.framework.model.DomainFolder; import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.ServiceProvider; @@ -38,11 +37,11 @@ import ghidra.util.Msg; * duty in that it opens files for DataTrees and for Tools (signaled via the interfaces it * implements). */ -public final class LinuxFileUrlHandler implements DataFlavorHandler, FileOpenDataFlavorHandler { +public final class LinuxFileUrlHandler implements DataTreeFlavorHandler, FileOpenDataFlavorHandler { @Override // This is for the DataFlavorHandler interface for handling node drops in DataTrees - public void handle(FrontEndTool tool, DataTree dataTree, GTreeNode destinationNode, + public void handle(PluginTool tool, DataTree dataTree, GTreeNode destinationNode, Object transferData, int dropAction) { DomainFolder folder = getDomainFolder(destinationNode); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/DiffUtility.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/DiffUtility.java index 7b4d9cbf4d..8d8c87e32a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/DiffUtility.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/DiffUtility.java @@ -193,11 +193,11 @@ public class DiffUtility extends SimpleDiffUtility { return otherProgram.getSymbolTable().createExternalLibrary(namespace.getName(), source); } else if (namespace instanceof GhidraClass) { - return otherProgram.getSymbolTable().createClass(otherParentNamespace, - namespace.getName(), source); + return otherProgram.getSymbolTable() + .createClass(otherParentNamespace, namespace.getName(), source); } - return otherProgram.getSymbolTable().createNameSpace(otherParentNamespace, - namespace.getName(), source); + return otherProgram.getSymbolTable() + .createNameSpace(otherParentNamespace, namespace.getName(), source); } // /** @@ -329,11 +329,11 @@ public class DiffUtility extends SimpleDiffUtility { if (toAddr == null) { return null; } - return otherProgram.getReferenceManager().getReference(fromAddr, toAddr, - ref.getOperandIndex()); + return otherProgram.getReferenceManager() + .getReference(fromAddr, toAddr, ref.getOperandIndex()); } - Reference otherRef = otherProgram.getReferenceManager().getPrimaryReferenceFrom(fromAddr, - ref.getOperandIndex()); + Reference otherRef = otherProgram.getReferenceManager() + .getPrimaryReferenceFrom(fromAddr, ref.getOperandIndex()); if (otherRef != null && ref.getToAddress().hasSameAddressSpace(otherRef.getToAddress())) { return otherRef; } @@ -357,11 +357,11 @@ public class DiffUtility extends SimpleDiffUtility { if (toAddr1 == null) { return null; } - return program.getReferenceManager().getReference(fromAddr1, toAddr1, - p2Ref.getOperandIndex()); + return program.getReferenceManager() + .getReference(fromAddr1, toAddr1, p2Ref.getOperandIndex()); } - Reference p1Ref = program.getReferenceManager().getPrimaryReferenceFrom(fromAddr1, - p2Ref.getOperandIndex()); + Reference p1Ref = program.getReferenceManager() + .getPrimaryReferenceFrom(fromAddr1, p2Ref.getOperandIndex()); if (p1Ref != null && p1Ref.getToAddress().hasSameAddressSpace(p2Ref.getToAddress())) { return p1Ref; } @@ -385,8 +385,9 @@ public class DiffUtility extends SimpleDiffUtility { otherAddr = getCompatibleAddress(program, addr, otherProgram); } // FIXME Should this be passing the Namespace? - return otherProgram.getExternalManager().addExtLocation(extLoc.getLibraryName(), - extLoc.getLabel(), otherAddr, extLoc.getSource()); + return otherProgram.getExternalManager() + .addExtLocation(extLoc.getLibraryName(), extLoc.getLabel(), otherAddr, + extLoc.getSource()); } /** @@ -707,6 +708,9 @@ public class DiffUtility extends SimpleDiffUtility { Address refAddress = getCompatibleAddress(program, location.refAddr, otherProgram); if (address != null) { + if (byteAddress == null) { + byteAddress = address; // Make sure the byte address isn't null. + } ProgramLocation otherLocation = new ProgramLocation(otherProgram, address, byteAddress, location.getComponentPath(), refAddress, 0, 0, 0); return otherLocation; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java index d0cb2dfefd..751d08d165 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java @@ -2555,7 +2555,7 @@ public class ProgramDiffDetails { } private void addColorAddress(StyledDocument doc, Address addr) { - String text = addr.toString(); + String text = (addr != null) ? addr.toString() : "no matching address"; color(ADDRESS_COLOR); try { doc.insertString(doc.getLength(), text, textAttrSet); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java index 5486eb65ac..11b468a459 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java @@ -43,7 +43,7 @@ public class SymbolicPropogator { // 1. How are "register-relative" varnodes distinguished based upon target space ? Not sure how we handle wrapping/truncation concerns. // 1) The offset is the only thing that could be used as a reference. - private static final int _POINTER_MIN_BOUNDS = 0x7fff; + private static final int _POINTER_MIN_BOUNDS = 0x100; // mask for sub-piece extraction private static long[] maskSize = { 0xffL, 0xffL, 0xffffL, 0xffffffL, 0xffffffffL, 0xffffffffffL, @@ -1836,7 +1836,7 @@ public class SymbolicPropogator { // see if the offset is a large constant offset from the symbolic space long offset = refLocation.getOffset(); - if (checkPossibleOffsetAddr(offset)) { + if (evaluator != null) { // symbolic spaces will have the name of the symbolic space be the register space // String spaceName = refLocation.getAddress().getAddressSpace().getName(); // Register register = vContext.getRegister(spaceName); @@ -1850,7 +1850,7 @@ public class SymbolicPropogator { // } // } else - if (evaluator == null) { + if (!vContext.isStackSymbolicSpace(refLocation) && evaluator != null) { Address constant = program.getAddressFactory().getAddress( (int) targetSpaceID.getOffset(), offset); Address newTarget = evaluator.evaluateConstant(vContext, instruction, @@ -2051,7 +2051,7 @@ public class SymbolicPropogator { */ private int getReferenceSpaceID(Instruction instruction, long offset) { // TODO: this should be passed to the client callback to make the decision - if (offset <= 4096 && offset >= -1) { + if (offset <= 4 && offset >= -1) { return -1; // don't make speculative reference to certain offset values } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java index 6266f9d77c..8be976f8d9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/VarnodeContext.java @@ -312,7 +312,7 @@ public class VarnodeContext implements ProcessorContext { /** * Return true if this varnode is stored in the symbolic stack space */ - private boolean isStackSymbolicSpace(Varnode varnode) { + public boolean isStackSymbolicSpace(Varnode varnode) { // symbolic spaces are off of a register, find the space AddressSpace regSpace = addrFactory.getAddressSpace(varnode.getSpace()); @@ -785,7 +785,9 @@ public class VarnodeContext implements ProcessorContext { * return the location that this register was last set * This is a transient thing, so it should only be used as a particular flow is being processed... * - * @param reg + * @param reg register to find last set location + * @param bval value to look for to differentiate set locations, null if don't care + * * @return address that the register was set. */ public Address getLastSetLocation(Register reg, BigInteger bval) { @@ -1256,6 +1258,13 @@ public class VarnodeContext implements ProcessorContext { // too big anyway,already extended as far as it will go. vnodeVal = createConstantVarnode(vnodeVal.getOffset(), out.getSize()); } + } else if (vnodeVal.isRegister() && vnodeVal.getSize() < out.getSize()) { + Register reg = getRegister(vnodeVal); + if (reg == null) { + throw notFoundExc; + } + int spaceID = getAddressSpace(reg.getName()); + vnodeVal = createVarnode(0,spaceID,out.getSize()); } return vnodeVal; } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java index 6e468ee1e2..792f46f2c9 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/framework/options/OptionsTest.java @@ -623,7 +623,7 @@ public class OptionsTest extends AbstractGenericTest { @Override public int hashCode() { - return 1;// set so that this listener gets called after the storingOptionsListnere + return 1;// set so that this listener gets called after the storingOptionsListener } } diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteField.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteField.java index b2e3dbd969..db7371f355 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteField.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteField.java @@ -15,8 +15,6 @@ */ package ghidra.app.plugin.core.byteviewer; -import ghidra.util.ColorUtils; - import java.awt.*; import java.math.BigInteger; @@ -28,6 +26,7 @@ import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager; import docking.widgets.fieldpanel.internal.PaintContext; import docking.widgets.fieldpanel.support.HighlightFactory; import docking.widgets.fieldpanel.support.RowColLocation; +import ghidra.util.ColorUtils; /** * Fields for the ByteViewer. This class extends the SimpleTextField to include @@ -52,7 +51,8 @@ public class ByteField extends SimpleTextField { * @param hlFactory the factory used to create highlights */ public ByteField(String text, FontMetrics fontMetrics, int startX, int width, - boolean allowCursorAtEnd, int fieldOffset, BigInteger index, HighlightFactory hlFactory) { + boolean allowCursorAtEnd, int fieldOffset, BigInteger index, + HighlightFactory hlFactory) { super(text, fontMetrics, startX, width, allowCursorAtEnd, hlFactory); this.fieldOffset = fieldOffset; @@ -64,7 +64,7 @@ public class ByteField extends SimpleTextField { public void paint(JComponent c, Graphics g, PaintContext context, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight) { paintSelection(g, colorManager, 0); - paintHighlights(g, hlFactory.getHighlights(text, -1)); + paintHighlights(g, hlFactory.getHighlights(this, text, -1)); g.setFont(metrics.getFont()); if (foregroundColor == null) { foregroundColor = context.getForeground(); diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java index b821e8b3c9..81ed547bfb 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/FieldFactory.java @@ -213,7 +213,7 @@ class FieldFactory { } @Override - public Highlight[] getHighlights(String text, int cursorTextOffset) { + public Highlight[] getHighlights(Field field, String text, int cursorTextOffset) { return provider.getHighlights(text, null, null, -1); } } diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java index bd828d425e..cb7ae28d6c 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/IndexFieldFactory.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +15,6 @@ */ package ghidra.app.plugin.core.byteviewer; -import ghidra.app.plugin.core.format.ByteBlockInfo; - import java.awt.Color; import java.awt.FontMetrics; import java.math.BigInteger; @@ -26,6 +23,7 @@ import docking.widgets.fieldpanel.field.Field; import docking.widgets.fieldpanel.field.SimpleTextField; import docking.widgets.fieldpanel.support.Highlight; import docking.widgets.fieldpanel.support.HighlightFactory; +import ghidra.app.plugin.core.format.ByteBlockInfo; /** * Implementation for the index/address field. @@ -145,7 +143,7 @@ class IndexFieldFactory { } @Override - public Highlight[] getHighlights(String text, int cursorTextOffset) { + public Highlight[] getHighlights(Field field, String text, int cursorTextOffset) { return NO_HIGHLIGHTS; } } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index af1165c37b..e4326eaffd 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -7333,8 +7333,12 @@ bool RuleConditionalMove::BoolExpress::evaluatePropagation(FlowBlock *root,FlowB if (root == branch) return true; // Can always propagate if there is no branch if (op->getParent() != branch) return true; // Can propagate if value formed before branch mustreconstruct = true; // Final op is performed in branch, so it must be reconstructed + if (in0->isFree() && !in0->isConstant()) return false; if (in0->isWritten() && (in0->getDef()->getParent()==branch)) return false; - if ((optype==2) && in1->isWritten() && (in1->getDef()->getParent()==branch)) return false; + if (optype == 2) { + if (in1->isFree() && !in1->isConstant()) return false; + if (in1->isWritten() && (in1->getDef()->getParent()==branch)) return false; + } return true; } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangTextField.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangTextField.java index 46020f53ca..4968cf02c6 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangTextField.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangTextField.java @@ -1,5 +1,6 @@ /* ### * IP: GHIDRA + * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -197,4 +198,8 @@ public class ClangTextField extends WrappingVerticalLayoutTextField { return lineNumberFieldElement.getStringWidth(); } + public int getLineNumber() { + String text = lineNumberFieldElement.getText().trim(); + return Integer.parseInt(text); + } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerHoverProvider.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerHoverProvider.java index 0f54d60bcb..63f1cc7c67 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerHoverProvider.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerHoverProvider.java @@ -76,8 +76,9 @@ public class DecompilerHoverProvider extends AbstractHoverProvider { Varnode vn = token.getVarnode(); if (vn != null) { - if (vn.getHigh() instanceof HighGlobal) { - reference = vn.getAddress(); + HighVariable highVar = vn.getHigh(); + if (highVar instanceof HighGlobal) { + reference = highVar.getRepresentative().getAddress(); } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerManager.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerManager.java index 617215edb3..f56bba85a7 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerManager.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerManager.java @@ -51,7 +51,7 @@ public class DecompilerManager { this.decompilerController = decompilerController; runManager = new RunManager("Decompiler", null); - decompiler = new Decompiler(options, options.getDefaultTimeout()); + decompiler = new Decompiler(options, 0); updateManager = new SwingUpdateManager(500, () -> doPendingDecompile()); } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java index aed2123de5..0a06f0f9d9 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java @@ -37,11 +37,11 @@ import docking.widgets.indexedscrollpane.IndexedScrollPane; import ghidra.app.decompiler.*; import ghidra.app.decompiler.component.hover.DecompilerHoverService; import ghidra.app.plugin.core.decompile.DecompileClipboardProvider; +import ghidra.app.plugin.core.decompile.actions.FieldBasedSearchLocation; import ghidra.program.model.address.*; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Program; -import ghidra.program.model.pcode.PcodeOp; -import ghidra.program.model.pcode.Varnode; +import ghidra.program.model.pcode.*; import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramSelection; import ghidra.util.*; @@ -175,6 +175,9 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field if (clipboard != null) { clipboard.selectionChanged(null); } + + // don't highlight search results across functions + currentSearchLocation = null; } private void setLocation(DecompileData oldData, DecompileData newData) { @@ -419,6 +422,10 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field } } + HighVariable highVar = vn.getHigh(); + if (highVar instanceof HighGlobal) { + vn = highVar.getRepresentative(); + } if (vn.isAddress()) { Address addr = vn.getAddress(); if (addr.isMemoryAddress()) { @@ -696,9 +703,21 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field } class SearchHighlightFactory implements HighlightFactory { + @Override - public Highlight[] getHighlights(String text, int cursorTextOffset) { - if (currentSearchLocation == null || cursorTextOffset == -1) { + public Highlight[] getHighlights(Field field, String text, int cursorTextOffset) { + if (currentSearchLocation == null) { + return new Highlight[0]; + } + + ClangTextField cField = (ClangTextField) field; + int highlightLine = cField.getLineNumber(); + + FieldLocation searchCursorLocation = + ((FieldBasedSearchLocation) currentSearchLocation).getFieldLocation(); + int searchLineNumber = searchCursorLocation.getIndex().intValue() + 1; + if (highlightLine != searchLineNumber) { + // only highlight the match on the actual line return new Highlight[0]; } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FieldBasedSearchLocation.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FieldBasedSearchLocation.java index 0d1434155c..191c32cc21 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FieldBasedSearchLocation.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FieldBasedSearchLocation.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,4 +38,9 @@ public class FieldBasedSearchLocation extends SearchLocation { public CursorPosition getCursorPosition() { return new DecompilerCursorPosition(fieldLocation); } + + @Override + protected String fieldsToString() { + return super.fieldsToString() + ", fieldLocation=" + fieldLocation; + } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java index 78c48a7cf4..70b23623e0 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java @@ -1,5 +1,6 @@ /* ### * IP: GHIDRA + * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -77,13 +78,20 @@ public class FindAction extends DockingAction { if (text != null) { dialog.setSearchText(text); } + // show over the root frame, so the user can still see the Decompiler window tool.showDialog(dialog); } protected FindDialog getFindDialog() { if (findDialog == null) { - findDialog = new FindDialog("Decompiler Find Text", new DecompilerSearcher()); + findDialog = new FindDialog("Decompiler Find Text", new DecompilerSearcher()) { + @Override + protected void dialogClosed() { + // clear the search results when the dialog is closed + decompilerPanel.setSearchResults(null); + } + }; findDialog.setHelpLocation(new HelpLocation("DecompilePlugin", "Find")); } return findDialog; diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java index 9240662b1a..04183ab7cd 100644 --- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java +++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/ProgramDiffPlugin.java @@ -441,6 +441,9 @@ public class ProgramDiffPlugin extends ProgramPlugin Address primaryByteAddr = SimpleDiffUtility.getCompatibleAddress(secondaryDiffProgram, byteAddr, primaryProgram); + if (primaryByteAddr == null) { + primaryByteAddr = primaryAddr; // Make sure the byte address isn't null. + } Address primaryRefAddr = SimpleDiffUtility.getCompatibleAddress(secondaryDiffProgram, refAddr, primaryProgram); ProgramLocation newP1Location = new ProgramLocation(primaryProgram, primaryAddr, @@ -463,7 +466,9 @@ public class ProgramDiffPlugin extends ProgramPlugin } ProgramLocation previousP1LocationAsP2 = DiffUtility .getCompatibleProgramLocation(primaryProgram, location, secondaryDiffProgram); - diffListingPanel.setCursorPosition(previousP1LocationAsP2); + if (previousP1LocationAsP2 != null) { + diffListingPanel.setCursorPosition(previousP1LocationAsP2); + } if (diffDetailsProvider != null && diffDetails != null) { diffDetailsProvider.locationChanged(previousP1Location); } @@ -749,7 +754,7 @@ public class ProgramDiffPlugin extends ProgramPlugin runSwing(() -> { MarkerSet selectionMarkers = getSelectionMarkers(); selectionMarkers.clearAll(); - selectionMarkers.add(p2SelectionAsP1); + selectionMarkers.add(p2Selection); }); diffListingPanel.setSelection(p2SelectionAsP1); @@ -798,9 +803,9 @@ public class ProgramDiffPlugin extends ProgramPlugin // Limit the apply to the selection in the view. AddressSet p2SelectionAsP1 = DiffUtility.getCompatibleAddressSet(p2Selection, primaryProgram); - AddressSet p1ApplySet = - p2SelectionAsP1.intersect(p1ViewAddrSet).subtract(addressesOnlyInP1).subtract( - compatibleOnlyInP2); + AddressSet p1ApplySet = p2SelectionAsP1.intersect(p1ViewAddrSet) + .subtract(addressesOnlyInP1) + .subtract(compatibleOnlyInP2); if (p1ApplySet.isEmpty()) { Msg.showInfo(getClass(), tool.getToolFrame(), "Apply Differences", (p2Selection.isEmpty()) ? "No diff selection in the current view." @@ -860,7 +865,7 @@ public class ProgramDiffPlugin extends ProgramPlugin // Right side markers need p1 addresses since they use p1 indexMap. MarkerSet diffMarkers = getDiffMarkers(); // Get right side markers for program 2. diffMarkers.clearAll(); - diffMarkers.add(p2DiffSetAsP1); + diffMarkers.add(p2DiffSet); MarkerSet codeViewerDiffMarkers = getCodeViewerMarkers(); // Get left side markers for program 1. codeViewerDiffMarkers.clearAll(); @@ -884,7 +889,7 @@ public class ProgramDiffPlugin extends ProgramPlugin AddressSet p1DiffHighlightSet = DiffUtility.getCompatibleAddressSet(p2Highlight, primaryProgram); p2DiffHighlight = p2Highlight; - diffMarkers.add(p1DiffHighlightSet); + diffMarkers.add(p2Highlight); codeViewerDiffMarkers.add(p1DiffHighlightSet); } @@ -1603,7 +1608,14 @@ public class ProgramDiffPlugin extends ProgramPlugin diffListingPanel.goTo(currentLocation); MarkerSet cursorMarkers = getCursorMarkers(); - cursorMarkers.setAddressSet(new AddressSet(currentLocation.getAddress())); + Address currentP2Address = currentLocation.getAddress(); + if (currentLocation.getProgram() != secondaryDiffProgram) { // Make sure address is from P2. + currentP2Address = SimpleDiffUtility.getCompatibleAddress(currentLocation.getProgram(), + currentLocation.getAddress(), secondaryDiffProgram); + } + if (currentP2Address != null) { + cursorMarkers.setAddressSet(new AddressSet(currentP2Address)); + } updatePgm2Enablement(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ActionContext.java b/Ghidra/Framework/Docking/src/main/java/docking/ActionContext.java index 3fed77d232..f9d950e63e 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/ActionContext.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/ActionContext.java @@ -47,7 +47,12 @@ public class ActionContext { } /** - * For Testing + * Constructor + * + * @param provider the ComponentProvider that generated this context. + * @param contextObject an optional contextObject that the ComponentProvider can provide + * @param sourceObject an optional source object; this can be anything that actions wish to + * later retrieve */ public ActionContext(ComponentProvider provider, Object contextObject, Object sourceObject) { this(provider, contextObject); @@ -55,8 +60,8 @@ public class ActionContext { } /** - * Returns the {@link #ComponentProvider} that generated this ActionContext - * @return + * Returns the {@link ComponentProvider} that generated this ActionContext + * @return the provider */ public ComponentProvider getComponentProvider() { return provider; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/SearchLocation.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/SearchLocation.java index 9dd7087fe0..064f241389 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/SearchLocation.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/SearchLocation.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,6 +59,10 @@ public class SearchLocation { @Override public String toString() { - return searchText + "[start=" + startIndexInclusive + ", end=" + endIndexInclusive + "]"; + return searchText + "[" + fieldsToString() + "]"; + } + + protected String fieldsToString() { + return startIndexInclusive + ", end=" + endIndexInclusive; } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ObjectChooserDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ObjectChooserDialog.java index 0aa754119b..7c9da99b61 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ObjectChooserDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/dialogs/ObjectChooserDialog.java @@ -63,7 +63,7 @@ public class ObjectChooserDialog extends DialogComponentProvider { table.addSelectionListener(t -> objectSelected(t)); - table.setItemPickListner(t -> objectPicked(t)); + table.setItemPickListener(t -> objectPicked(t)); return table; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ClippingTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ClippingTextField.java index 506e1f8667..bb25ba0477 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ClippingTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ClippingTextField.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -129,8 +128,8 @@ public class ClippingTextField implements TextField { int x = findX(col) + startX; - return new Rectangle(x, -textElement.getHeightAbove(), 2, textElement.getHeightAbove() + - textElement.getHeightBelow()); + return new Rectangle(x, -textElement.getHeightAbove(), 2, + textElement.getHeightAbove() + textElement.getHeightBelow()); } /** @@ -315,7 +314,7 @@ public class ClippingTextField implements TextField { if (cursorLoc != null) { cursorTextOffset = screenLocationToTextOffset(cursorLoc.row(), cursorLoc.col()); } - paintHighlights(g, hlFactory.getHighlights(getString(), cursorTextOffset)); + paintHighlights(g, hlFactory.getHighlights(this, getString(), cursorTextOffset)); } protected void paintSelection(Graphics g, FieldBackgroundColorManager colorManager, int row, @@ -344,10 +343,10 @@ public class ClippingTextField implements TextField { } protected void paintHighlights(Graphics g, Highlight[] highlights) { - for (int i = 0; i < highlights.length; i++) { - int startCol = Math.max(highlights[i].getStart(), 0); - int endCol = Math.min(highlights[i].getEnd(), getString().length()); - Color c = highlights[i].getColor(); + for (Highlight highlight : highlights) { + int startCol = Math.max(highlight.getStart(), 0); + int endCol = Math.min(highlight.getEnd(), getString().length()); + Color c = highlight.getColor(); if (endCol >= startCol) { int start = findX(startCol); int end = findX(endCol + 1); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ReverseClippingTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ReverseClippingTextField.java index 3ffa173ccb..bffa921952 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ReverseClippingTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ReverseClippingTextField.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -142,8 +141,8 @@ public class ReverseClippingTextField implements TextField { int x = findX(col) + textStartX; - return new Rectangle(x, -textElement.getHeightAbove(), 2, textElement.getHeightAbove() + - textElement.getHeightBelow()); + return new Rectangle(x, -textElement.getHeightAbove(), 2, + textElement.getHeightAbove() + textElement.getHeightBelow()); } /** @@ -336,8 +335,7 @@ public class ReverseClippingTextField implements TextField { private void paintDots(Graphics g, int x) { int pos = 1; // skip one pixel for (int i = 0; i < 3; i++) { - if (pos < DOT_DOT_DOT_WIDTH - 2) { // don't paint too close to next - // field. + if (pos < DOT_DOT_DOT_WIDTH - 2) { // don't paint too close to next field g.drawRect(x + pos, -2, 1, 1); pos += 4; // add in size of dot and padding } @@ -349,14 +347,14 @@ public class ReverseClippingTextField implements TextField { if (cursorLoc != null) { cursorTextOffset = screenLocationToTextOffset(cursorLoc.row(), cursorLoc.col()); } - paintHighlights(g, hlFactory.getHighlights(getString(), cursorTextOffset)); + paintHighlights(g, hlFactory.getHighlights(this, getString(), cursorTextOffset)); } protected void paintHighlights(Graphics g, Highlight[] highlights) { - for (int i = 0; i < highlights.length; i++) { - int startCol = Math.max(highlights[i].getStart() - startingCharIndex, 0); - int endCol = Math.min(highlights[i].getEnd() - startingCharIndex, getString().length()); - Color c = highlights[i].getColor(); + for (Highlight highlight : highlights) { + int startCol = Math.max(highlight.getStart() - startingCharIndex, 0); + int endCol = Math.min(highlight.getEnd() - startingCharIndex, getString().length()); + Color c = highlight.getColor(); if (endCol >= startCol) { int start = findX(startCol); int end = findX(endCol + 1); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleTextField.java index a4dbdbbbaf..f75903abb6 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleTextField.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -202,7 +201,7 @@ public class SimpleTextField implements Field { public void paint(JComponent c, Graphics g, PaintContext context, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight) { paintSelection(g, colorManager, 0); - paintHighlights(g, hlFactory.getHighlights(text, -1)); + paintHighlights(g, hlFactory.getHighlights(this, text, -1)); g.setFont(metrics.getFont()); if (foregroundColor == null) { foregroundColor = context.getForeground(); @@ -226,10 +225,10 @@ public class SimpleTextField implements Field { } protected void paintHighlights(Graphics g, Highlight[] highlights) { - for (int i = 0; i < highlights.length; i++) { - int startCol = Math.max(highlights[i].getStart(), 0); - int endCol = Math.min(highlights[i].getEnd(), text.length()); - Color c = highlights[i].getColor(); + for (Highlight highlight : highlights) { + int startCol = Math.max(highlight.getStart(), 0); + int endCol = Math.min(highlight.getEnd(), text.length()); + Color c = highlight.getColor(); if (endCol >= startCol) { int start = findX(startCol); int end = findX(endCol + 1); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/VerticalLayoutTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/VerticalLayoutTextField.java index 7f4e79319a..dad543cad9 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/VerticalLayoutTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/VerticalLayoutTextField.java @@ -268,7 +268,7 @@ public class VerticalLayoutTextField implements TextField { cursorRow = cursorLoc.row(); } - Highlight[] highlights = hlFactory.getHighlights(getText(), cursorTextOffset); + Highlight[] highlights = hlFactory.getHighlights(this, getText(), cursorTextOffset); int columns = 0; int n = subFields.size(); Color fieldBackgroundColor = colorManager.getBackgroundColor(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/TestBigLayoutModel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/TestBigLayoutModel.java index 371314727f..c2803615ea 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/TestBigLayoutModel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/internal/TestBigLayoutModel.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +16,6 @@ package docking.widgets.fieldpanel.internal; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.math.BigInteger; import java.util.ArrayList; @@ -33,11 +30,8 @@ import docking.widgets.indexedscrollpane.IndexedScrollPane; public class TestBigLayoutModel implements LayoutModel { private static final Highlight[] NO_HIGHLIGHTS = new Highlight[0]; - private static final HighlightFactory hlFactory = new HighlightFactory() { - public Highlight[] getHighlights(String text, int cursorTextOffset) { - return NO_HIGHLIGHTS; - } - }; + private static final HighlightFactory hlFactory = + (field, text, cursorTextOffset) -> NO_HIGHLIGHTS; ArrayList listeners = new ArrayList(); FontMetrics fm; @@ -86,15 +80,13 @@ public class TestBigLayoutModel implements LayoutModel { if (index.compareTo(numIndexes) >= 0) { return null; } - String text = - name + ": This is line " + index + - " More text to make line longer abcdefghijklmnopqrstuvwxyzabcdefghijk"; + String text = name + ": This is line " + index + + " More text to make line longer abcdefghijklmnopqrstuvwxyzabcdefghijk"; FieldElement fe1 = new TextFieldElement(new AttributedString(text, Color.BLACK, fm), 0, 0); FieldElement fe2 = new TextFieldElement(new AttributedString("More text", Color.BLACK, fm), 0, 0); - SingleRowLayout layout = - new SingleRowLayout(new ClippingTextField(20, 300, fe1, hlFactory), - new ClippingTextField(330, 100, fe2, hlFactory)); + SingleRowLayout layout = new SingleRowLayout(new ClippingTextField(20, 300, fe1, hlFactory), + new ClippingTextField(330, 100, fe2, hlFactory)); if (index.intValue() >= startBigSizes && index.intValue() <= endBigSizes) { layout.insertSpaceAbove(30); @@ -143,12 +135,7 @@ public class TestBigLayoutModel implements LayoutModel { contentPane.setLayout(new BorderLayout()); contentPane.add(scrollPanel); JButton button = new JButton("Hit Me"); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - model.updateData(1000, 2000); - } - }); + button.addActionListener(e -> model.updateData(1000, 2000)); contentPane.add(button, BorderLayout.SOUTH); frame.pack(); frame.setVisible(true); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/HighlightFactory.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/HighlightFactory.java index 3d46ca7e66..8ac6c85d17 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/HighlightFactory.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/HighlightFactory.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +15,18 @@ */ package docking.widgets.fieldpanel.support; +import docking.widgets.fieldpanel.field.Field; + public interface HighlightFactory { + /** - * Returns the highlights for the given text. - * @param text the text to be considered for highlighting. + * Returns the highlights for the given text + * + * @param field the field that is requesting the highlight + * @param text the text to be considered for highlighting * @param cursorTextOffset the position in the given text of the cursor. A -1 indicates the - * cursor is not in this field. - * @return an array of highlights to be rendered. + * cursor is not in this field. + * @return an array of highlights to be rendered */ - public Highlight[] getHighlights(String text, int cursorTextOffset); + public Highlight[] getHighlights(Field field, String text, int cursorTextOffset); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableWidget.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableWidget.java index d85f891941..b8a6a2cfb5 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableWidget.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableWidget.java @@ -133,7 +133,7 @@ public class GTableWidget extends JPanel { listener.itemPicked(gFilterTable.getSelectedRowObject()); } - public void setItemPickListner(TableItemPickedListener listener) { + public void setItemPickListener(TableItemPickedListener listener) { this.listener = listener; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java index 2b60c2e053..ea7c7ee19a 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/GTree.java @@ -867,7 +867,7 @@ public class GTree extends JPanel implements BusyListener { tree.getModel().addTreeModelListener(listener); } - public void removeGTModelListner(TreeModelListener listener) { + public void removeGTModelListener(TreeModelListener listener) { tree.getModel().removeTreeModelListener(listener); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/support/GTreeNodeTransferable.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/support/GTreeNodeTransferable.java index db434c3374..7a517077b1 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/support/GTreeNodeTransferable.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/tree/support/GTreeNodeTransferable.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,69 +18,75 @@ package docking.widgets.tree.support; import java.awt.datatransfer.*; import java.io.IOException; import java.util.List; +import java.util.Objects; import docking.widgets.tree.GTreeNode; /** - * A transferable for sharing data via drag/drop and clipboard operations for GTrees. + * A transferable for sharing data via drag/drop and clipboard operations for GTrees */ public class GTreeNodeTransferable implements Transferable { - private final List selectedData; - private final GTreeTransferHandler transferHandler; + private final List selectedData; + private final GTreeTransferHandler transferHandler; - /** - * Creates this transferable based upon the selected data and uses the given transfer - * handler to perform {@link Transferable} operations. - * @param handler the handler used to perform transfer operations. - * @param selectedData The - */ - public GTreeNodeTransferable( GTreeTransferHandler handler, List selectedData) { - this.selectedData = selectedData; - this.transferHandler = handler; - } - - /** - * Returns all of the original selected data contained by this transferable. - * @return all of the original selected data contained by this transferable - */ - public List getAllData() { - return selectedData; - } - - /** - * Gets the transfer data from the selection based upon the given flavor. - * @param transferNodes The nodes from which to get the data. - * @param flavor The flavor of data to retreive from the given selection. - * @return the transfer data from the selection based upon the given flavor. - * @throws UnsupportedFlavorException if the given flavor is not one of the supported flavors - * returned by {@link #getSupportedDataFlavors(List)}. - */ - public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { - return transferHandler.getTransferData(selectedData, flavor); - } - - /** - * Returns the DataFlavors for the types of data that this transferable supports, based upon - * the given selection. - * @param transferNodes The nodes to base the DataFlavor selection upon. - * @return the DataFlavors for the types of data that this transferable supports, based upon - * the given selection. + /** + * Creates this transferable based upon the selected data and uses the given transfer + * handler to perform {@link Transferable} operations + * + * @param handler the handler used to perform transfer operations + * @param selectedData The selected tree nodes */ - public DataFlavor[] getTransferDataFlavors() { - return transferHandler.getSupportedDataFlavors(selectedData); - } + public GTreeNodeTransferable(GTreeTransferHandler handler, List selectedData) { + this.transferHandler = Objects.requireNonNull(handler); + this.selectedData = Objects.requireNonNull(selectedData); + } - /** - * A convenience method to determine if this transferable supports the given flavor. - * @return true if this transferable supports the given flavor. - */ - public boolean isDataFlavorSupported(DataFlavor flavor) { - DataFlavor[] flavors = transferHandler.getSupportedDataFlavors(selectedData); - for(int i=0;i getAllData() { + return selectedData; + } + + /** + * Gets the transfer data from the selection based upon the given flavor + + * @param flavor The flavor of data to retrieve from the given selection. + * @return the transfer data from the selection based upon the given flavor. + * @throws UnsupportedFlavorException if the given flavor is not one of the supported flavors + * returned by {@link #getTransferDataFlavors()} + */ + @Override + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + return transferHandler.getTransferData(selectedData, flavor); + } + + /** + * Returns the DataFlavors for the types of data that this transferable supports, based upon + * the given selection + * + * @return the DataFlavors for the types of data that this transferable supports, based upon + * the given selection + */ + @Override + public DataFlavor[] getTransferDataFlavors() { + return transferHandler.getSupportedDataFlavors(selectedData); + } + + /** + * A convenience method to determine if this transferable supports the given flavor + * @return true if this transferable supports the given flavor + */ + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + DataFlavor[] flavors = transferHandler.getSupportedDataFlavors(selectedData); + for (DataFlavor f : flavors) { + if (f.equals(flavor)) { + return true; + } + } + return false; + } } diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/FlowLayoutTextFieldTest.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/FlowLayoutTextFieldTest.java index 675ec2b03f..604bd46201 100644 --- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/FlowLayoutTextFieldTest.java +++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/FlowLayoutTextFieldTest.java @@ -15,7 +15,7 @@ */ package docking.widgets.fieldpanel; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import java.awt.*; @@ -40,11 +40,8 @@ public class FlowLayoutTextFieldTest extends AbstractGenericTest { @Before public void setUp() throws Exception { - HighlightFactory factory = new HighlightFactory() { - @Override - public Highlight[] getHighlights(String text, int cursorTextOffset) { - return new Highlight[] { new Highlight(4, 4, Color.YELLOW) }; - } + HighlightFactory factory = (field, text, cursorTextOffset) -> { + return new Highlight[] { new Highlight(4, 4, Color.YELLOW) }; }; Font font = new Font("Times New Roman", 0, 14); diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java index 6d77b473e9..dacf10ab15 100644 --- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java +++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java @@ -15,7 +15,7 @@ */ package docking.widgets.fieldpanel; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import java.awt.*; @@ -40,11 +40,8 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest { @Before public void setUp() throws Exception { - HighlightFactory factory = new HighlightFactory() { - @Override - public Highlight[] getHighlights(String text, int cursorTextOffset) { - return new Highlight[] { new Highlight(4, 4, Color.YELLOW) }; - } + HighlightFactory factory = (field, text, cursorTextOffset) -> { + return new Highlight[] { new Highlight(4, 4, Color.YELLOW) }; }; Font font = new Font("Times New Roman", 0, 14); diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FileSystem.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FileSystem.java index 4cfd3fb7aa..6db0208eef 100644 --- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FileSystem.java +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/store/FileSystem.java @@ -254,7 +254,7 @@ public interface FileSystem { /** * Adds the given listener to be notified of file system changes. - * @param listener the listner to be added. + * @param listener the listener to be added. */ public void addFileSystemListener(FileSystemListener listener); diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/PathHighlightListner.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/PathHighlightListener.java similarity index 95% rename from Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/PathHighlightListner.java rename to Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/PathHighlightListener.java index 68529067a9..366c5dd90f 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/PathHighlightListner.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/PathHighlightListener.java @@ -15,7 +15,7 @@ */ package ghidra.graph.viewer.edge; -public interface PathHighlightListner { +public interface PathHighlightListener { /** * Called when the a path is highlighted. diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/VisualGraphPathHighlighter.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/VisualGraphPathHighlighter.java index 0bc45cd701..f6bf916447 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/VisualGraphPathHighlighter.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/VisualGraphPathHighlighter.java @@ -99,7 +99,7 @@ public class VisualGraphPathHighlighter> postDominanceFuture; private CompletableFuture circuitFuture; - private PathHighlightListner listener = isHover -> { + private PathHighlightListener listener = isHover -> { // stub }; @@ -108,7 +108,7 @@ public class VisualGraphPathHighlighter doUpdateFocusedVertex()); - public VisualGraphPathHighlighter(VisualGraph graph, PathHighlightListner listener) { + public VisualGraphPathHighlighter(VisualGraph graph, PathHighlightListener listener) { this.graph = graph; if (listener != null) { this.listener = listener; diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/app/util/FileOpenDataFlavorHandler.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/util/FileOpenDataFlavorHandler.java index f4bdd441cc..4852c85c39 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/app/util/FileOpenDataFlavorHandler.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/app/util/FileOpenDataFlavorHandler.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +15,14 @@ */ package ghidra.app.util; -import ghidra.framework.plugintool.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.dnd.DropTargetDropEvent; -import java.awt.datatransfer.*; -import java.awt.dnd.*; +import ghidra.framework.plugintool.PluginTool; +/** + * Interface for classes that will handle drop actions for files dropped onto the tool + */ public interface FileOpenDataFlavorHandler { - public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f); + public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/app/util/FileOpenDataFlavorHandlerService.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/util/FileOpenDataFlavorHandlerService.java deleted file mode 100644 index 687e6aed63..0000000000 --- a/Ghidra/Framework/Project/src/main/java/ghidra/app/util/FileOpenDataFlavorHandlerService.java +++ /dev/null @@ -1,37 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * 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 ghidra.app.util; - -import ghidra.framework.PluggableServiceRegistry; -import ghidra.framework.main.datatree.DataTreeDragNDropHandler; -import ghidra.framework.main.datatree.VersionInfoTransferable; - -public class FileOpenDataFlavorHandlerService { - static { - PluggableServiceRegistry.registerPluggableService(FileOpenDataFlavorHandlerService.class, new FileOpenDataFlavorHandlerService()); - } - - public static void registerDataFlavorHandlers() { - FileOpenDataFlavorHandlerService factory = PluggableServiceRegistry.getPluggableService(FileOpenDataFlavorHandlerService.class); - factory.doRegisterDataFlavorHandlers(); - } - - protected void doRegisterDataFlavorHandlers() { - FileOpenDropHandler.addDataFlavorHandler(DataTreeDragNDropHandler.localDomainFileFlavor, new LocalTreeNodeFlavorHandler()); - FileOpenDropHandler.addDataFlavorHandler(VersionInfoTransferable.localVersionInfoFlavor, new LocalTreeNodeFlavorHandler()); - } -} diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/app/util/FileOpenDropHandler.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/util/FileOpenDropHandler.java index 7a16da0504..6a4e4428ce 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/app/util/FileOpenDropHandler.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/app/util/FileOpenDropHandler.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +15,6 @@ */ package ghidra.app.util; -import ghidra.framework.plugintool.PluginTool; -import ghidra.util.CascadedDropTarget; - import java.awt.Component; import java.awt.Container; import java.awt.datatransfer.DataFlavor; @@ -33,6 +29,8 @@ import javax.swing.CellRendererPane; import docking.DropTargetHandler; import docking.dnd.DropTgtAdapter; import docking.dnd.Droppable; +import ghidra.framework.plugintool.PluginTool; +import ghidra.util.CascadedDropTarget; /** * Handles drag/drop events on a given component such that a file @@ -44,9 +42,6 @@ import docking.dnd.Droppable; public class FileOpenDropHandler implements DropTargetHandler, Droppable, ContainerListener { private static HashMap handlers = new HashMap(); - static { - FileOpenDataFlavorHandlerService.registerDataFlavorHandlers(); - } private DropTgtAdapter dropTargetAdapter; private DropTarget globalDropTarget; @@ -75,11 +70,13 @@ public class FileOpenDropHandler implements DropTargetHandler, Droppable, Contai /** * Dispose this drop handler. */ + @Override public void dispose() { deinitializeComponents(component); globalDropTarget.removeDropTargetListener(dropTargetAdapter); } + @Override public boolean isDropOk(DropTargetDragEvent e) { Set flavors = handlers.keySet(); for (DataFlavor dataFlavor : flavors) { @@ -90,6 +87,7 @@ public class FileOpenDropHandler implements DropTargetHandler, Droppable, Contai return false; } + @Override public void add(Object obj, DropTargetDropEvent e, DataFlavor f) { FileOpenDataFlavorHandler handler = handlers.get(f); if (handler != null) { @@ -97,24 +95,28 @@ public class FileOpenDropHandler implements DropTargetHandler, Droppable, Contai } } + @Override public void dragUnderFeedback(boolean ok, DropTargetDragEvent e) { // nothing to display or do } + @Override public void undoDragUnderFeedback() { // nothing to display or do } private void initializeComponents(Component comp) { - if (comp instanceof CellRendererPane) + if (comp instanceof CellRendererPane) { return; + } if (comp instanceof Container) { Container c = (Container) comp; c.addContainerListener(this); Component comps[] = c.getComponents(); - for (Component element : comps) + for (Component element : comps) { initializeComponents(element); + } } DropTarget primaryDropTarget = comp.getDropTarget(); if (primaryDropTarget != null) { @@ -123,15 +125,17 @@ public class FileOpenDropHandler implements DropTargetHandler, Droppable, Contai } private void deinitializeComponents(Component comp) { - if (comp instanceof CellRendererPane) + if (comp instanceof CellRendererPane) { return; + } if (comp instanceof Container) { Container c = (Container) comp; c.removeContainerListener(this); Component comps[] = c.getComponents(); - for (Component element : comps) + for (Component element : comps) { deinitializeComponents(element); + } } DropTarget dt = comp.getDropTarget(); if (dt instanceof CascadedDropTarget) { @@ -141,15 +145,18 @@ public class FileOpenDropHandler implements DropTargetHandler, Droppable, Contai } } + @Override public void componentAdded(ContainerEvent e) { initializeComponents(e.getChild()); } + @Override public void componentRemoved(ContainerEvent e) { deinitializeComponents(e.getChild()); } - public static void addDataFlavorHandler(DataFlavor dataFlavor, FileOpenDataFlavorHandler handler) { + public static void addDataFlavorHandler(DataFlavor dataFlavor, + FileOpenDataFlavorHandler handler) { handlers.put(dataFlavor, handler); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/app/util/LocalTreeNodeFlavorHandler.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/util/LocalTreeNodeFlavorHandler.java deleted file mode 100644 index fe87e5cf59..0000000000 --- a/Ghidra/Framework/Project/src/main/java/ghidra/app/util/LocalTreeNodeFlavorHandler.java +++ /dev/null @@ -1,72 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * 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 ghidra.app.util; - -import ghidra.framework.main.GetVersionedObjectTask; -import ghidra.framework.main.datatree.*; -import ghidra.framework.model.*; -import ghidra.framework.plugintool.PluginTool; - -import java.awt.datatransfer.DataFlavor; -import java.awt.dnd.DropTargetDropEvent; -import java.util.List; - -final class LocalTreeNodeFlavorHandler implements FileOpenDataFlavorHandler { - public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f) { - if (f.equals(DataTreeDragNDropHandler.localDomainFileFlavor)) { - List files = (List) obj; - DomainFile[] domainFiles = new DomainFile[files.size()]; - for (int i = 0; i < files.size(); i++) { - domainFiles[i] = (DomainFile) files.get(i); - } - tool.acceptDomainFiles(domainFiles); - } - else if (f.equals(DataTreeDragNDropHandler.localDomainFileTreeFlavor)) { - List files = (List) obj; - DomainFile[] domainFiles = new DomainFile[files.size()]; - for (int i = 0; i < files.size(); i++) { - DomainFileNode node = (DomainFileNode) files.get(i); - domainFiles[i] = node.getDomainFile(); - } - tool.acceptDomainFiles(domainFiles); - } - else if (f.equals(VersionInfoTransferable.localVersionInfoFlavor)) { - VersionInfo info = (VersionInfo) obj; - Project project = tool.getProject(); - ProjectData projectData = project.getProjectData(); - DomainFile file = projectData.getFile(info.getDomainFilePath()); - DomainObject versionedObj = getVersionedObject(tool, file, info.getVersionNumber()); - - if (versionedObj != null) { - DomainFile domainFile = versionedObj.getDomainFile(); - if (domainFile != null) { - tool.acceptDomainFiles(new DomainFile[] { domainFile }); - } - versionedObj.release(this); - } - } - } - - private DomainObject getVersionedObject(PluginTool tool, DomainFile file, int versionNumber) { - GetVersionedObjectTask task = new GetVersionedObjectTask(this, file, versionNumber); - tool.execute(task, 250); - return task.getVersionedObject(); - } -} diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/app/util/LocalVersionInfoFlavorHandler.java b/Ghidra/Framework/Project/src/main/java/ghidra/app/util/LocalVersionInfoFlavorHandler.java deleted file mode 100644 index 62d2bd7e75..0000000000 --- a/Ghidra/Framework/Project/src/main/java/ghidra/app/util/LocalVersionInfoFlavorHandler.java +++ /dev/null @@ -1,47 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * 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 ghidra.app.util; - -import ghidra.framework.main.*; -import ghidra.framework.main.datatree.*; -import ghidra.framework.model.*; -import ghidra.framework.plugintool.*; - -import java.awt.datatransfer.*; -import java.awt.dnd.*; - -final class LocalVersionInfoFlavorHandler implements - FileOpenDataFlavorHandler { - public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f) { - VersionInfo info = (VersionInfo) obj; - - DomainFile file = tool.getProject().getProjectData().getFile(info.getDomainFilePath()); - GetVersionedObjectTask task = new GetVersionedObjectTask(this, file, - info.getVersionNumber()); - tool.execute(task, 250); - DomainObject versionedObj = task.getVersionedObject(); - - if (versionedObj != null) { - DomainFile vfile = versionedObj.getDomainFile(); - tool.acceptDomainFiles(new DomainFile[] {vfile}); - versionedObj.release(this); - } - } -} diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataActionContext.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataActionContext.java index 179325b06a..c2acecdda6 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataActionContext.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataActionContext.java @@ -30,6 +30,7 @@ public class ProjectDataActionContext extends ActionContext implements DomainFil private Component comp; private boolean isActiveProject; private ProjectData projectData; + private boolean isTransient; public ProjectDataActionContext(ComponentProvider provider, ProjectData projectData, Object contextObject, List selectedFolders, @@ -112,4 +113,20 @@ public class ProjectDataActionContext extends ActionContext implements DomainFil } return false; } + + /** + * Transient data is that which will appear in a temporary project dialog + * @param isTransient true if transient + */ + public void setTransient(boolean isTransient) { + this.isTransient = isTransient; + } + + /** + * Transient data is that which will appear in a temporary project dialog + * @return true if transient + */ + public boolean isTransient() { + return isTransient; + } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataContextAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataContextAction.java index 5e9daa17eb..dd853ebb3a 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataContextAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataContextAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,20 +25,42 @@ public abstract class ProjectDataContextAction extends DockingAction { } @Override - public final boolean isEnabledForContext(ActionContext actionContext) { + public boolean isEnabledForContext(ActionContext actionContext) { if (!(actionContext instanceof ProjectDataActionContext)) { return false; } + ProjectDataActionContext context = (ProjectDataActionContext) actionContext; + if (ignoreTransientProject(context)) { + return false; + } + return isEnabledForContext(context); } + protected boolean ignoreTransientProject(ProjectDataActionContext context) { + if (supportsTransientProjectData()) { + return false; + } + return context.isTransient(); + } + + /** + * Signals that this action can work on normal project data, as well as transient data. + * Transient data is that which will appear in a temporary project dialog. + * + * @return true if this action works on transient project data + */ + protected boolean supportsTransientProjectData() { + return false; + } + protected boolean isEnabledForContext(ProjectDataActionContext context) { return context.hasOneOrMoreFilesAndFolders(); } @Override - public final void actionPerformed(ActionContext context) { + public void actionPerformed(ActionContext context) { actionPerformed((ProjectDataActionContext) context); } @@ -59,7 +80,7 @@ public abstract class ProjectDataContextAction extends DockingAction { @Override public boolean isAddToPopup(ActionContext context) { - if (!(context instanceof ProjectDataActionContext)) { + if (!isEnabledForContext(context)) { return false; } return isAddToPopup((ProjectDataActionContext) context); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataContextToggleAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataContextToggleAction.java index d1fcb555f5..2b9dc7b39c 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataContextToggleAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataContextToggleAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,10 +29,32 @@ public abstract class ProjectDataContextToggleAction extends ToggleDockingAction if (!(actionContext instanceof ProjectDataActionContext)) { return false; } + ProjectDataActionContext context = (ProjectDataActionContext) actionContext; + if (ignoreTransientProject(context)) { + return false; + } + return isEnabledForContext(context); } + protected boolean ignoreTransientProject(ProjectDataActionContext context) { + if (supportsTransientProjectData()) { + return false; + } + return context.isTransient(); + } + + /** + * Signals that this action can work on normal project data, as well as transient data. + * Transient data is that which will appear in a temporary project dialog. + * + * @return true if this action works on transient project data + */ + protected boolean supportsTransientProjectData() { + return false; + } + protected boolean isEnabledForContext(ProjectDataActionContext context) { return context.hasOneOrMoreFilesAndFolders(); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataTreeContextAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataTreeContextAction.java index 137b73986f..7df40012df 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataTreeContextAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatable/ProjectDataTreeContextAction.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +15,9 @@ */ package ghidra.framework.main.datatable; -import ghidra.framework.main.datatree.ProjectDataTreeActionContext; import docking.ActionContext; import docking.action.DockingAction; +import ghidra.framework.main.datatree.ProjectDataTreeActionContext; public abstract class ProjectDataTreeContextAction extends DockingAction { @@ -31,10 +30,32 @@ public abstract class ProjectDataTreeContextAction extends DockingAction { if (!(actionContext instanceof ProjectDataTreeActionContext)) { return false; } + ProjectDataTreeActionContext context = (ProjectDataTreeActionContext) actionContext; + if (ignoreTransientProject(context)) { + return false; + } + return isEnabledForContext(context); } + protected boolean ignoreTransientProject(ProjectDataActionContext context) { + if (supportsTransientProjectData()) { + return false; + } + return context.isTransient(); + } + + /** + * Signals that this action can work on normal project data, as well as transient data. + * Transient data is that which will appear in a temporary project dialog. + * + * @return true if this action works on transient project data + */ + protected boolean supportsTransientProjectData() { + return false; + } + protected boolean isEnabledForContext(ProjectDataTreeActionContext context) { return context.hasOneOrMoreFilesAndFolders(); } @@ -60,7 +81,7 @@ public abstract class ProjectDataTreeContextAction extends DockingAction { @Override public boolean isAddToPopup(ActionContext context) { - if (!(context instanceof ProjectDataTreeActionContext)) { + if (!isEnabledForContext(context)) { return false; } return isAddToPopup((ProjectDataTreeActionContext) context); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataFlavorHandlerService.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataFlavorHandlerService.java deleted file mode 100644 index 3d6bedb22b..0000000000 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataFlavorHandlerService.java +++ /dev/null @@ -1,38 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * 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 ghidra.framework.main.datatree; - -import ghidra.framework.PluggableServiceRegistry; - -public class DataFlavorHandlerService { - static { - PluggableServiceRegistry.registerPluggableService(DataFlavorHandlerService.class, new DataFlavorHandlerService()); - } - - public static void registerDataFlavorHandlers() { - DataFlavorHandlerService factory = PluggableServiceRegistry.getPluggableService(DataFlavorHandlerService.class); - factory.doRegisterDataFlavorHandlers(); - } - - protected void doRegisterDataFlavorHandlers() { - final LocalTreeNodeHandler localTreeNodeHandler = new LocalTreeNodeHandler(); - DataTreeDragNDropHandler.addActiveDataFlavorHandler(DataTreeDragNDropHandler.localDomainFileTreeFlavor, localTreeNodeHandler); - DataTreeDragNDropHandler.addActiveDataFlavorHandler(VersionInfoTransferable.localVersionInfoFlavor, new LocalVersionInfoHandler()); - - DataTreeDragNDropHandler.addInactiveDataFlavorHandler(DataTreeDragNDropHandler.localDomainFileTreeFlavor, localTreeNodeHandler); - } -} diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTree.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTree.java index 513e2aab26..d2e3c8d145 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTree.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTree.java @@ -16,8 +16,7 @@ package ghidra.framework.main.datatree; import java.awt.Component; -import java.awt.event.*; -import java.util.List; +import java.awt.event.KeyEvent; import javax.swing.JTree; import javax.swing.KeyStroke; @@ -30,20 +29,13 @@ import docking.widgets.tree.support.GTreeRenderer; import ghidra.framework.main.FrontEndTool; /** - * Tree that shows the folders and domain files in a Project. + * Tree that shows the folders and domain files in a Project */ public class DataTree extends GTree { - static { - DataFlavorHandlerService.registerDataFlavorHandlers(); - } private boolean isActive; private DataTreeDragNDropHandler dragNDropHandler; - /** - * Constructor - * @param folder root domain folder for the project. - */ DataTree(FrontEndTool tool, GTreeRootNode root) { super(root); @@ -53,30 +45,11 @@ public class DataTree extends GTree { docking.ToolTipManager.sharedInstance().registerComponent(this); - //When the user right clicks, change selection to what the mouse was under - addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON3) { - //Find the would-be newly selected path - TreePath newPath = getPathForLocation(evt.getX(), evt.getY()); - if (newPath == null) { - return; - } - //Determine if the path is already selected--If so, do not change the selection - TreePath[] paths = getSelectionPaths(); - if (paths != null) { - for (TreePath element : paths) { - if (element.equals(newPath)) { - return; - } - } - } - } - } - }); - dragNDropHandler = new DataTreeDragNDropHandler(tool, this, isActive); - setDragNDropHandler(dragNDropHandler); + if (tool != null) { + dragNDropHandler = new DataTreeDragNDropHandler(tool, this, isActive); + setDragNDropHandler(dragNDropHandler); + } + initializeKeyEvents(); } @@ -92,74 +65,10 @@ public class DataTree extends GTree { KeyStroke.getKeyStroke(KeyEvent.VK_X, DockingUtils.CONTROL_KEY_MODIFIER_MASK)); } - void setProjectActive(boolean b) { - dragNDropHandler.setProjectActive(b); - } - - /** - * Return true if this path has all of its subpaths expanded. - */ - public boolean allPathsExpanded(TreePath path) { - - GTreeNode node = (GTreeNode) path.getLastPathComponent(); - if (node.isLeaf()) { - return true; + void setProjectActive(boolean isActive) { + if (dragNDropHandler != null) { + dragNDropHandler.setProjectActive(isActive); } - if (isCollapsed(path)) { - return false; - } - - boolean allLeaves = true; - - List children = node.getChildren(); - for (GTreeNode child : children) { - if (child.isLeaf()) { - continue; - } - allLeaves = false; - if (!isExpanded(child.getTreePath())) { - return false; - } - - if (!allPathsExpanded(child.getTreePath())) { - return false; - } - } - if (allLeaves) { - return isExpanded(path); - } - return true; - } - - /** - * Return true if this path has all of its subpaths collapsed. - */ - public boolean allPathsCollapsed(TreePath path) { - GTreeNode node = (GTreeNode) path.getLastPathComponent(); - - if (isExpanded(path)) { - return false; - } - boolean allLeaves = true; // variable for knowing whether all children are leaves - - node.getChildren(); - for (GTreeNode child : node) { - if (child.isLeaf()) { - continue; - } - allLeaves = false; - if (!isCollapsed(child.getTreePath())) { - return false; - } - - if (!allPathsCollapsed(child.getTreePath())) { - return false; - } - } - if (allLeaves) { - return isCollapsed(path); - } - return true; } public void clearSelection() { @@ -183,20 +92,7 @@ public class DataTree extends GTree { getJTree().stopEditing(); } - ////////////////////////////////////////////////////////////////////// - // *** private methods - ////////////////////////////////////////////////////////////////////// - /** - * Tree cell renderer to use the appropriate icons for the - * DataTreeNodes. - */ private class DataTreeCellRenderer extends GTreeRenderer { - - /** - * Configures the renderer based on the passed in components. - * The icon is set according to value, expanded, and leaf - * parameters. - */ @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean doesHaveFocus) { @@ -209,7 +105,5 @@ public class DataTree extends GTree { } return this; } - } - } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeClipboardUtils.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeClipboardUtils.java index 40cdb3a720..f522152a2a 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeClipboardUtils.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeClipboardUtils.java @@ -23,6 +23,7 @@ import javax.swing.tree.TreePath; import docking.dnd.GClipboard; import docking.widgets.tree.GTreeNode; +import docking.widgets.tree.support.GTreeNodeTransferable; import ghidra.util.Msg; /** @@ -35,14 +36,8 @@ public class DataTreeClipboardUtils { * Static instance of a callback handler that is notified when the clipboard is changed * and our data is discarded. */ - private static final ClipboardOwner DATATREE_CLIPBOARD_OWNER = new ClipboardOwner() { - @Override - public void lostOwnership(Clipboard clipboard, Transferable contents) { - // This is called when something other than this class modifies the clipboard - // and our data is discarded. - clearCuttables(contents); - } - }; + private static final ClipboardOwner DATATREE_CLIPBOARD_OWNER = + (clipboard, contents) -> clearCuttables(contents); /** * Pushes the GTreeNodes in the specified TreePath array to the clipboard. @@ -59,8 +54,9 @@ public class DataTreeClipboardUtils { GTreeNode node = (GTreeNode) element.getLastPathComponent(); list.add(node); } - DataTreeNodeTransferable contents = - new DataTreeNodeTransferable(tree.getDragNDropHandler(), list); + + GTreeNodeTransferable contents = + new GTreeNodeTransferable(tree.getDragNDropHandler(), list); try { clipboard.setContents(contents, DATATREE_CLIPBOARD_OWNER); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeDragNDropHandler.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeDragNDropHandler.java index a7b9f32770..70293082f3 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeDragNDropHandler.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeDragNDropHandler.java @@ -30,9 +30,7 @@ import ghidra.util.Msg; import ghidra.util.exception.AssertException; public class DataTreeDragNDropHandler implements GTreeDragNDropHandler { - private static Map activeProjectDropFlavorHandlerMap = - new HashMap<>(); - private static Map inactiveProjectDropFlavorHandlerMap = + private static Map activeProjectDropFlavorHandlerMap = new HashMap<>(); public static DataFlavor localDomainFileTreeFlavor = createLocalTreeNodeFlavor(); public static DataFlavor localDomainFileFlavor = createLocalTreeFlavor(); @@ -79,29 +77,31 @@ public class DataTreeDragNDropHandler implements GTreeDragNDropHandler { public void drop(GTreeNode destination, Transferable transferable, int dropAction) { DataFlavor[] transferDataFlavors = transferable.getTransferDataFlavors(); for (DataFlavor dataFlavor : transferDataFlavors) { - DataFlavorHandler flavorHandler = getFlavorHandler(dataFlavor); + DataTreeFlavorHandler flavorHandler = getFlavorHandler(dataFlavor); if (flavorHandler != null) { - try { - Object transferData = transferable.getTransferData(dataFlavor); - flavorHandler.handle(tool, tree, destination, transferData, dropAction); - } - catch (UnsupportedFlavorException e) { - throw new AssertException( - "Got unsupported flavor from using a supported flavor"); - } - catch (IOException e) { - Msg.showError(this, null, "IO Error", "Error during drop", e); - } + handleDrop(destination, transferable, dropAction, dataFlavor, flavorHandler); return; } } } - private DataFlavorHandler getFlavorHandler(DataFlavor flavor) { - if (isActiveProject) { - return activeProjectDropFlavorHandlerMap.get(flavor); + private void handleDrop(GTreeNode destination, Transferable transferable, int dropAction, + DataFlavor dataFlavor, DataTreeFlavorHandler flavorHandler) { + + try { + Object transferData = transferable.getTransferData(dataFlavor); + flavorHandler.handle(tool, tree, destination, transferData, dropAction); } - return inactiveProjectDropFlavorHandlerMap.get(flavor); + catch (UnsupportedFlavorException e) { + throw new AssertException("Got unsupported flavor from using a supported flavor"); + } + catch (IOException e) { + Msg.showError(this, null, "IO Error", "Error during drop", e); + } + } + + private DataTreeFlavorHandler getFlavorHandler(DataFlavor flavor) { + return activeProjectDropFlavorHandlerMap.get(flavor); } @Override @@ -134,13 +134,6 @@ public class DataTreeDragNDropHandler implements GTreeDragNDropHandler { @Override public DataFlavor[] getSupportedDataFlavors(List transferNodes) { return allSupportedFlavors; -// Set keySet = null; -// if (isActiveProject) { -// keySet = activeProjectDropFlavorHandlerMap.keySet(); -// } else { -// keySet = inactiveProjectDropFlavorHandlerMap.keySet(); -// } -// return keySet.toArray(new DataFlavor[keySet.size()]); } @Override @@ -196,24 +189,15 @@ public class DataTreeDragNDropHandler implements GTreeDragNDropHandler { return false; } - public static void addActiveDataFlavorHandler(DataFlavor flavor, DataFlavorHandler handler) { + public static void addActiveDataFlavorHandler(DataFlavor flavor, DataTreeFlavorHandler handler) { activeProjectDropFlavorHandlerMap.put(flavor, handler); } - public static void addInactiveDataFlavorHandler(DataFlavor flavor, DataFlavorHandler handler) { - inactiveProjectDropFlavorHandlerMap.put(flavor, handler); - } - - public static DataFlavorHandler removeActiveDataFlavorHandler(DataFlavor flavor) { + public static DataTreeFlavorHandler removeActiveDataFlavorHandler(DataFlavor flavor) { return activeProjectDropFlavorHandlerMap.remove(flavor); } - public static DataFlavorHandler removeInctiveDataFlavorHandler(DataFlavor flavor) { - return inactiveProjectDropFlavorHandlerMap.remove(flavor); - } - public void setProjectActive(boolean b) { isActiveProject = b; } - } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataFlavorHandler.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeFlavorHandler.java similarity index 69% rename from Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataFlavorHandler.java rename to Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeFlavorHandler.java index f63e22469c..18aba84d63 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataFlavorHandler.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeFlavorHandler.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +15,13 @@ */ package ghidra.framework.main.datatree; -import ghidra.framework.main.FrontEndTool; import docking.widgets.tree.GTreeNode; +import ghidra.framework.plugintool.PluginTool; -public interface DataFlavorHandler { - public void handle(FrontEndTool tool, DataTree dataTree, GTreeNode destinationNode, - Object transferData, int dropAction); +/** + * Interface for classes that will handle drop actions for {@link DataTree}s. + */ +public interface DataTreeFlavorHandler { + public void handle(PluginTool tool, DataTree dataTree, GTreeNode destinationNode, + Object transferData, int dropAction); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeNodeTransferable.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeNodeTransferable.java deleted file mode 100644 index 793a178278..0000000000 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/DataTreeNodeTransferable.java +++ /dev/null @@ -1,30 +0,0 @@ -/* ### - * IP: GHIDRA - * REVIEWED: YES - * - * 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 ghidra.framework.main.datatree; - -import java.util.List; - -import docking.widgets.tree.GTreeNode; -import docking.widgets.tree.support.GTreeNodeTransferable; -import docking.widgets.tree.support.GTreeTransferHandler; - -public class DataTreeNodeTransferable extends GTreeNodeTransferable { - public DataTreeNodeTransferable(GTreeTransferHandler handler, List selectedData) { - super(handler, selectedData); - } - -} diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/LocalTreeNodeHandler.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/LocalTreeNodeHandler.java index a31fcc76af..bcc70cdd84 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/LocalTreeNodeHandler.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/LocalTreeNodeHandler.java @@ -15,29 +15,55 @@ */ package ghidra.framework.main.datatree; +import java.awt.datatransfer.DataFlavor; import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTargetDropEvent; import java.io.IOException; import java.util.List; -import javax.swing.SwingUtilities; - import docking.widgets.tree.GTreeNode; import docking.widgets.tree.GTreeState; -import ghidra.framework.main.FrontEndTool; +import ghidra.app.util.FileOpenDataFlavorHandler; import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFolder; +import ghidra.framework.plugintool.PluginTool; import ghidra.util.Msg; +import ghidra.util.SystemUtilities; import ghidra.util.exception.DuplicateFileException; import ghidra.util.exception.FileInUseException; import ghidra.util.task.*; -final class LocalTreeNodeHandler implements DataFlavorHandler { +public final class LocalTreeNodeHandler + implements DataTreeFlavorHandler, FileOpenDataFlavorHandler { + private DataTree dataTree; private GTreeState treeState; + @Override + public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f) { + + if (f.equals(DataTreeDragNDropHandler.localDomainFileFlavor)) { + List files = (List) obj; + DomainFile[] domainFiles = new DomainFile[files.size()]; + for (int i = 0; i < files.size(); i++) { + domainFiles[i] = (DomainFile) files.get(i); + } + tool.acceptDomainFiles(domainFiles); + } + else if (f.equals(DataTreeDragNDropHandler.localDomainFileTreeFlavor)) { + List files = (List) obj; + DomainFile[] domainFiles = new DomainFile[files.size()]; + for (int i = 0; i < files.size(); i++) { + DomainFileNode node = (DomainFileNode) files.get(i); + domainFiles[i] = node.getDomainFile(); + } + tool.acceptDomainFiles(domainFiles); + } + } + @Override @SuppressWarnings("unchecked") - public void handle(FrontEndTool tool, DataTree tree, GTreeNode destinationNode, + public void handle(PluginTool tool, DataTree tree, GTreeNode destinationNode, Object transferData, int dropAction) { this.dataTree = tree; @@ -52,12 +78,9 @@ final class LocalTreeNodeHandler implements DataFlavorHandler { new TaskLauncher(task, dataTree, 1000); if (treeState != null) { // is set to null if drag results in a task - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - treeState.updateStateForMovedNodes(); - dataTree.restoreTreeState(treeState); - } + SystemUtilities.runSwingLater(() -> { + treeState.updateStateForMovedNodes(); + dataTree.restoreTreeState(treeState); }); } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/LocalVersionInfoHandler.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/LocalVersionInfoHandler.java index 3dc8e451ec..294f45895d 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/LocalVersionInfoHandler.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/LocalVersionInfoHandler.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,42 +13,64 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * - */ package ghidra.framework.main.datatree; -import ghidra.framework.client.*; -import ghidra.framework.main.FrontEndTool; -import ghidra.framework.model.DomainFile; -import ghidra.framework.model.DomainFolder; -import ghidra.util.task.TaskLauncher; - +import java.awt.datatransfer.DataFlavor; +import java.awt.dnd.DropTargetDropEvent; import java.io.IOException; import docking.widgets.tree.GTreeNode; +import ghidra.app.util.FileOpenDataFlavorHandler; +import ghidra.framework.client.*; +import ghidra.framework.main.GetVersionedObjectTask; +import ghidra.framework.model.*; +import ghidra.framework.plugintool.PluginTool; +import ghidra.util.task.TaskLauncher; -final class LocalVersionInfoHandler implements DataFlavorHandler { - public void handle(FrontEndTool tool, DataTree dataTree, GTreeNode destinationNode, - Object transferData, int dropAction) { - DomainFolder folder = getDomainFolder(destinationNode); - - VersionInfo info = (VersionInfo) transferData; - RepositoryAdapter rep = tool.getProject().getProjectData().getRepository(); - try { - if (rep != null) { - rep.connect(); - } - DomainFile file = tool.getProject().getProjectData().getFile(info.getDomainFilePath()); - if (file != null) { - new TaskLauncher(new CopyFileVersionTask(file, info.getVersionNumber(), folder), dataTree, 500); - } - } - catch (NotConnectedException exc) {} - catch (IOException exc) { - ClientUtil.handleException(rep, exc, "Repository Connection", tool.getToolFrame()); - } - } +public final class LocalVersionInfoHandler + implements DataTreeFlavorHandler, FileOpenDataFlavorHandler { + + @Override + public void handle(PluginTool tool, Object obj, DropTargetDropEvent e, DataFlavor f) { + VersionInfo info = (VersionInfo) obj; + + DomainFile file = tool.getProject().getProjectData().getFile(info.getDomainFilePath()); + GetVersionedObjectTask task = + new GetVersionedObjectTask(this, file, info.getVersionNumber()); + tool.execute(task, 250); + DomainObject versionedObj = task.getVersionedObject(); + + if (versionedObj != null) { + DomainFile vfile = versionedObj.getDomainFile(); + tool.acceptDomainFiles(new DomainFile[] { vfile }); + versionedObj.release(this); + } + } + + @Override + public void handle(PluginTool tool, DataTree dataTree, GTreeNode destinationNode, + Object transferData, int dropAction) { + DomainFolder folder = getDomainFolder(destinationNode); + + VersionInfo info = (VersionInfo) transferData; + RepositoryAdapter rep = tool.getProject().getProjectData().getRepository(); + try { + if (rep != null) { + rep.connect(); + } + DomainFile file = tool.getProject().getProjectData().getFile(info.getDomainFilePath()); + if (file != null) { + new TaskLauncher(new CopyFileVersionTask(file, info.getVersionNumber(), folder), + dataTree, 500); + } + } + catch (NotConnectedException exc) { + // not sure why we squash this? + } + catch (IOException exc) { + ClientUtil.handleException(rep, exc, "Repository Connection", tool.getToolFrame()); + } + } private DomainFolder getDomainFolder(GTreeNode destinationNode) { if (destinationNode instanceof DomainFolderNode) { diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/ProjectDataTreeActionContext.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/ProjectDataTreeActionContext.java index 63eba46ece..cffbbc0d28 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/ProjectDataTreeActionContext.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/ProjectDataTreeActionContext.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +15,13 @@ */ package ghidra.framework.main.datatree; -import ghidra.framework.main.datatable.ProjectDataActionContext; -import ghidra.framework.model.*; - import java.util.List; import javax.swing.tree.TreePath; import docking.ComponentProvider; +import ghidra.framework.main.datatable.ProjectDataActionContext; +import ghidra.framework.model.*; public class ProjectDataTreeActionContext extends ProjectDataActionContext { @@ -52,7 +50,7 @@ public class ProjectDataTreeActionContext extends ProjectDataActionContext { return selectionPaths; } - public DataTree getDataTree() { + public DataTree getTree() { return tree; } } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/ProjectDataTreePanel.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/ProjectDataTreePanel.java index 1651798827..a3514f5748 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/ProjectDataTreePanel.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/datatree/ProjectDataTreePanel.java @@ -55,33 +55,26 @@ public class ProjectDataTreePanel extends JPanel { private ChangeManager changeMgr; private boolean isActiveProject; - private FrontEndTool tool; // may be null if the panel is inside of the - + // these may be null if the panel is inside of a dialog + private FrontEndTool tool; private FrontEndPlugin plugin; - // data tree dialog - /** - * Construct an empty panel that is going to be used as the active - * panel. - * @param tool front end tool + * Construct an empty panel that is going to be used as the active panel + * @param plugin front end plugin */ public ProjectDataTreePanel(FrontEndPlugin plugin) { this(null, true, plugin, null); } /** - * Construct a new DataTreePanel. + * Constructor + * * @param projectName name of project - * @param projectData object that provides access to all the user data - * folders in a project * @param isActiveProject true if the project is active, and the * data tree may be modified - * @param tool front end tool; will be null if the panel is used in a dialog - * @param actionMgr class to handle enablement of actions; an ActionManager - * is passed in when several data tree panels all need to use the - * same ActionManager, e.g., the viewed projects in the front end tool; - * actionMgr will be null if the panel is used in a dialog + * @param plugin front end plugin; will be null if the panel is used in a dialog + * @param filter optional filter that is used to hide programs from view */ public ProjectDataTreePanel(String projectName, boolean isActiveProject, FrontEndPlugin plugin, DomainFileFilter filter) { @@ -211,9 +204,6 @@ public class ProjectDataTreePanel extends JPanel { } } - /** - * Set the help location for the data tree. - */ public void setHelpLocation(HelpLocation helpLocation) { HelpService help = Help.getHelpService(); help.registerHelp(tree, helpLocation); @@ -228,8 +218,9 @@ public class ProjectDataTreePanel extends JPanel { } /** - * Get the number of selected items in the tree. - * These could be either DomainFile's or DomainFolder's. + * Get the number of selected items in the tree. These could be either files or folders. + * + * @return the number of selected items in the tree. */ public int getSelectedItemCount() { return tree.getSelectionCount(); @@ -279,47 +270,31 @@ public class ProjectDataTreePanel extends JPanel { tree.removeGTreeSelectionListener(l); } - /** - * Add a mouse listener to the data tree. - */ public void addTreeMouseListener(MouseListener l) { tree.addMouseListener(l); } - /** - * Remove the mouse listener from the data tree. - */ public void removeTreeMouseListener(MouseListener l) { tree.removeMouseListener(l); } - /** - * Set the preferred size of the scroll pane that contains the - * data tree. - */ public void setPreferredTreePanelSize(Dimension d) { tree.setPreferredSize(d); } - /** - * Get the project data that this data tree panel is operating on. - */ public ProjectData getProjectData() { return projectData; } /** * Notification that the project was renamed; update the root node name - * and reload the node. + * and reload the node + * @param newName the new project name */ public void projectRenamed(String newName) { updateProjectName(newName); } - /** - * Notification that panel is being disposed. - * - */ public void dispose() { if (projectData != null) { projectData.removeDomainFolderChangeListener(changeMgr); @@ -328,10 +303,12 @@ public class ProjectDataTreePanel extends JPanel { } /** - * Get the data tree node that is selected. - * @param e mouse event for the popup; may be null if this is being - * called as a result of the key binding pressed - * @return null if there is no selection + * Get the data tree node that is selected + * + * @param provider the provider with which to construct the new context + * @param e mouse event for the popup; may be null if this is being called as a result of + * the key binding pressed + * @return the new context; null if there is no selection */ public ActionContext getActionContext(ComponentProvider provider, MouseEvent e) { if (root instanceof NoProjectNode) { @@ -360,13 +337,13 @@ public class ProjectDataTreePanel extends JPanel { } } - return new ProjectDataTreeActionContext(provider, projectData, selectionPaths, - domainFolderList, domainFileList, tree, isActiveProject); + ProjectDataTreeActionContext context = new ProjectDataTreeActionContext(provider, + projectData, selectionPaths, domainFolderList, domainFileList, tree, isActiveProject); + boolean isTransient = tool == null; // null for stand-alone dialog, not the project's tree + context.setTransient(isTransient); + return context; } - /** - * get the data tree for this data tree panel. - */ public DataTree getDataTree() { return tree; } @@ -380,17 +357,10 @@ public class ProjectDataTreePanel extends JPanel { tree.setFilterVisible(enabled); } - /** - * Return true if this data tree panel is listening to domain folder - * changes. - */ boolean domainFolderListenerAdded() { return changeMgr != null; } - /** - * Get the folder change listener. - */ DomainFolderChangeListener getFolderChangeListener() { return changeMgr; } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCollapseAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCollapseAction.java index fdec297512..6e60a4ad5b 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCollapseAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCollapseAction.java @@ -33,7 +33,7 @@ public class ProjectDataCollapseAction extends ProjectDataTreeContextAction { @Override protected void actionPerformed(ProjectDataTreeActionContext context) { - DataTree tree = context.getDataTree(); + DataTree tree = context.getTree(); TreePath[] paths = context.getSelectionPaths(); collapse(tree, paths[0]); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCopyAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCopyAction.java index 858fb08888..c1207ec325 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCopyAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCopyAction.java @@ -40,7 +40,7 @@ public class ProjectDataCopyAction extends ProjectDataCopyCutBaseAction { protected void actionPerformed(ProjectDataTreeActionContext context) { TreePath[] paths = adjustSelectionPaths(context.getSelectionPaths()); - DataTreeClipboardUtils.setClipboardContents(context.getDataTree(), paths); + DataTreeClipboardUtils.setClipboardContents(context.getTree(), paths); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCutAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCutAction.java index 9341248252..ee80774d39 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCutAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataCutAction.java @@ -40,7 +40,7 @@ public class ProjectDataCutAction extends ProjectDataCopyCutBaseAction { protected void actionPerformed(ProjectDataTreeActionContext context) { TreePath[] paths = adjustSelectionPaths(context.getSelectionPaths()); - DataTreeClipboardUtils.setClipboardContents(context.getDataTree(), paths); + DataTreeClipboardUtils.setClipboardContents(context.getTree(), paths); markNodesCut(paths); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataExpandAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataExpandAction.java index 393457277e..576ce289c3 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataExpandAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataExpandAction.java @@ -33,7 +33,7 @@ public class ProjectDataExpandAction extends ProjectDataTreeContextAction { @Override protected void actionPerformed(ProjectDataTreeActionContext context) { - DataTree tree = context.getDataTree(); + DataTree tree = context.getTree(); TreePath[] paths = context.getSelectionPaths(); expand(tree, paths[0]); } diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataNewFolderAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataNewFolderAction.java index 2e658cf93d..44d8dddf06 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataNewFolderAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataNewFolderAction.java @@ -41,6 +41,12 @@ public class ProjectDataNewFolderAction extends ProjectDataContextAction { markHelpUnnecessary(); } + @Override + protected boolean supportsTransientProjectData() { + // we allow the user to create new folders even in transient projects + return true; + } + @Override protected void actionPerformed(ProjectDataActionContext context) { createNewFolder(context); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataPasteAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataPasteAction.java index 9bbaee00c5..5bf29f7245 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataPasteAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataPasteAction.java @@ -44,7 +44,7 @@ public class ProjectDataPasteAction extends ProjectDataCopyCutBaseAction { GTreeNode node = (GTreeNode) context.getContextObject(); DomainFolderNode destNode = getFolderForNode(node); - paste(context.getDataTree(), destNode); + paste(context.getTree(), destNode); } @Override diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataReadOnlyAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataReadOnlyAction.java index b7e8837547..4ca5086dcf 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataReadOnlyAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataReadOnlyAction.java @@ -50,6 +50,10 @@ public class ProjectDataReadOnlyAction extends ProjectDataContextToggleAction { if (context.getFolderCount() != 0 || context.getFileCount() != 1) { return false; } + if (ignoreTransientProject(context)) { + return false; + } + DomainFile domainFile = context.getSelectedFiles().get(0); setSelected(domainFile.isReadOnly()); return true; diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataSelectAction.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataSelectAction.java index f584babf9d..f3fa36668e 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataSelectAction.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/main/projectdata/actions/ProjectDataSelectAction.java @@ -36,7 +36,7 @@ public class ProjectDataSelectAction extends ProjectDataTreeContextAction { @Override protected void actionPerformed(ProjectDataTreeActionContext context) { - DataTree tree = context.getDataTree(); + DataTree tree = context.getTree(); TreePath[] paths = context.getSelectionPaths(); GTreeNode node = (GTreeNode) paths[0].getLastPathComponent(); selectAllChildren(tree, node); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/GProgressBar.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/GProgressBar.java index 99b316b2e1..29eb284923 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/GProgressBar.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/task/gui/GProgressBar.java @@ -59,12 +59,12 @@ public class GProgressBar extends JPanel { private Timer updateTimer; private EmptyBorderButton cancelButton; - private CancelledListener cancelledListner; + private CancelledListener cancelledListener; - public GProgressBar(CancelledListener cancelledListner, boolean includeTextField, + public GProgressBar(CancelledListener cancelledListener, boolean includeTextField, boolean includeCancelButton, boolean includeAnimatedIcon, float fontSize) { super(new BorderLayout(5, 1)); - this.cancelledListner = cancelledListner; + this.cancelledListener = cancelledListener; this.fontSize = fontSize; buildProgressPanel(includeTextField, includeCancelButton, includeAnimatedIcon); @@ -199,13 +199,13 @@ public class GProgressBar extends JPanel { } public void cancel() { - if (cancelledListner != null) { - cancelledListner.cancelled(); + if (cancelledListener != null) { + cancelledListener.cancelled(); } } public void setCancelledListener(CancelledListener listener) { - this.cancelledListner = listener; + this.cancelledListener = listener; } private void buildProgressPanel(boolean includeTextField, boolean includeCancelButton, diff --git a/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g b/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g index ba0bffac28..7170783b57 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g +++ b/Ghidra/Framework/SoftwareModeling/src/main/antlr/ghidra/sleigh/grammar/SleighCompiler.g @@ -1473,8 +1473,10 @@ expr_apply returns [Object value] ; expr_operands returns [VectorSTL value] + scope Return; @init { $value = new VectorSTL(); + $Return::noReturn = false; } : (e=expr { value.push_back(e); })* ; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java index d75023a482..8a8bd055f2 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/PcodeDataTypeManager.java @@ -261,10 +261,7 @@ public class PcodeDataTypeManager { if (type instanceof Array) { return buildType(type, size); } - if (type instanceof FunctionDefinition) { - return buildType(type, size); - } - if (type.getLength() <= 0) { + if (!(type instanceof FunctionDefinition) && type.getLength() <= 0) { return buildType(type, size); } StringBuilder resBuf = new StringBuilder(); @@ -541,7 +538,7 @@ public class PcodeDataTypeManager { } resBuf.append(" ACCESS_LEVEL = Set.of(Modifier.PUBLIC); - private Reporter log; private File destDir; @@ -122,8 +120,7 @@ public class JsonDoclet implements Doclet { //@formatter:off ElementFilter.typesIn(docEnv.getIncludedElements()) .stream() - .filter(el -> el.getModifiers().containsAll(ACCESS_LEVEL)) - .filter(el -> el.getKind().equals(ElementKind.CLASS)) + .filter(el -> el.getKind().equals(ElementKind.CLASS) || el.getKind().equals(ElementKind.INTERFACE)) .forEach(el -> writeJsonToFile(classToJson(el), el.getQualifiedName())); //@formatter:on @@ -211,9 +208,6 @@ public class JsonDoclet implements Doclet { JSONArray methodArray = new JSONArray(); for (Element el : classElement.getEnclosedElements()) { - if (!el.getModifiers().containsAll(ACCESS_LEVEL)) { - continue; - } JSONObject obj = new JSONObject(); obj.put("name", el.getSimpleName().toString()); diff --git a/GhidraBuild/Skeleton/data/build.xml b/GhidraBuild/Skeleton/data/build.xml new file mode 100644 index 0000000000..1e2a6276bc --- /dev/null +++ b/GhidraBuild/Skeleton/data/build.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradleScripts/distribution.gradle b/gradleScripts/distribution.gradle index 7aaf03b2f4..15260c088c 100644 --- a/gradleScripts/distribution.gradle +++ b/gradleScripts/distribution.gradle @@ -134,6 +134,10 @@ task createJsondocs(type: Javadoc, description: 'Generate JSON docs for all proj it.sourceSets.test.compileClasspath }) + // Generate at package level because user may try to get help directly on an object they have + // rather than its public interface. + options.addBooleanOption("package", true) + // Some internal packages are not public and need to be exported. options.addMultilineStringsOption("-add-exports").setValue(["java.desktop/sun.awt.image=ALL-UNNAMED", "java.desktop/sun.awt=ALL-UNNAMED", diff --git a/licenses/FAMFAMFAM_MINI_ICONS_-_Public_Domain.txt b/licenses/FAMFAMFAM_Mini_Icons_-_Public_Domain.txt similarity index 100% rename from licenses/FAMFAMFAM_MINI_ICONS_-_Public_Domain.txt rename to licenses/FAMFAMFAM_Mini_Icons_-_Public_Domain.txt diff --git a/licenses/certification.manifest b/licenses/certification.manifest index 94ef6577e7..b11781ed93 100644 --- a/licenses/certification.manifest +++ b/licenses/certification.manifest @@ -5,7 +5,8 @@ Christian_Plattner.txt||LICENSE||||END| Creative_Commons_Attribution_2.5.html||LICENSE||||END| Crystal_Clear_Icons_-_LGPL_2.1.txt||LICENSE||||END| FAMFAMFAM_Icons_-_CC_2.5.txt||LICENSE||||END| -FAMFAMFAM_MINI_ICONS_-_Public_Domain.txt||LICENSE||||END| +FAMFAMFAM_Mini_Icons_-_Public_Domain.txt||LICENSE||||END| +FAMFAMFAM Mini Icons - Public Domain.txt||LICENSE||||END| GPL_2_With_Classpath_Exception.txt||LICENSE||||END| JDOM_License.txt||LICENSE||||END| Jython_License.txt||LICENSE||||END|