Updated some copy actions to use a task monitor

This commit is contained in:
dragonmacher 2023-06-09 13:09:05 -04:00
parent f3ebcf679b
commit 49a3dcebe7
3 changed files with 121 additions and 52 deletions

View file

@ -49,6 +49,7 @@ import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.program.util.*; import ghidra.program.util.*;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.task.CancellableIterator;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
import util.CollectionUtils; import util.CollectionUtils;
@ -184,22 +185,22 @@ public class CodeBrowserClipboardProvider extends ByteCopier
public Transferable copySpecial(ClipboardType copyType, TaskMonitor monitor) { public Transferable copySpecial(ClipboardType copyType, TaskMonitor monitor) {
if (copyType == ADDRESS_TEXT_TYPE) { if (copyType == ADDRESS_TEXT_TYPE) {
return copyAddress(); return copyAddress(monitor);
} }
else if (copyType == ADDRESS_TEXT_WITH_OFFSET_TYPE) { else if (copyType == ADDRESS_TEXT_WITH_OFFSET_TYPE) {
return copySymbolString(); return copySymbolString(monitor);
} }
else if (copyType == CODE_TEXT_TYPE) { else if (copyType == CODE_TEXT_TYPE) {
return copyCode(monitor); return copyCode(monitor);
} }
else if (copyType == LABELS_COMMENTS_TYPE) { else if (copyType == LABELS_COMMENTS_TYPE) {
return copyLabelsComments(true, true); return copyLabelsComments(true, true, monitor);
} }
else if (copyType == LABELS_TYPE) { else if (copyType == LABELS_TYPE) {
return copyLabelsComments(true, false); return copyLabelsComments(true, false, monitor);
} }
else if (copyType == COMMENTS_TYPE) { else if (copyType == COMMENTS_TYPE) {
return copyLabelsComments(false, true); return copyLabelsComments(false, true, monitor);
} }
return copyBytes(copyType, monitor); return copyBytes(copyType, monitor);
@ -308,17 +309,18 @@ public class CodeBrowserClipboardProvider extends ByteCopier
return new NonLabelStringTransferable(location.getOperandRepresentation()); return new NonLabelStringTransferable(location.getOperandRepresentation());
} }
private Transferable copyAddress() { private Transferable copyAddress(TaskMonitor monitor) {
AddressSetView addrs = getSelectedAddresses(); AddressSetView addrs = getSelectedAddresses();
Iterable<Address> it = addrs.getAddresses(true); Iterable<Address> iterable = addrs.getAddresses(true);
CancellableIterator<Address> it = new CancellableIterator<>(iterable.iterator(), monitor);
return createStringTransferable(StringUtils.join(it, "\n")); return createStringTransferable(StringUtils.join(it, "\n"));
} }
private Transferable copySymbolString() { private Transferable copySymbolString(TaskMonitor monitor) {
Listing listing = currentProgram.getListing(); Listing listing = currentProgram.getListing();
List<String> strings = new ArrayList<>(); List<String> strings = new ArrayList<>();
CodeUnitIterator codeUnits = listing.getCodeUnits(getSelectedAddresses(), true); CodeUnitIterator codeUnits = listing.getCodeUnits(getSelectedAddresses(), true);
while (codeUnits.hasNext()) { while (codeUnits.hasNext() && !monitor.isCancelled()) {
CodeUnit cu = codeUnits.next(); CodeUnit cu = codeUnits.next();
Address addr = cu.getAddress(); Address addr = cu.getAddress();
Function function = listing.getFunctionContaining(addr); Function function = listing.getFunctionContaining(addr);
@ -379,11 +381,12 @@ public class CodeBrowserClipboardProvider extends ByteCopier
return createStringTransferable(copyBytesAsString(set, false, TaskMonitor.DUMMY)); return createStringTransferable(copyBytesAsString(set, false, TaskMonitor.DUMMY));
} }
private CodeUnitInfoTransferable copyLabelsComments(boolean copyLabels, boolean copyComments) { private CodeUnitInfoTransferable copyLabelsComments(boolean copyLabels, boolean copyComments,
TaskMonitor monitor) {
AddressSetView addressSet = getSelectedAddresses(); AddressSetView addressSet = getSelectedAddresses();
List<CodeUnitInfo> list = new ArrayList<>(); List<CodeUnitInfo> list = new ArrayList<>();
Address startAddr = addressSet.getMinAddress(); Address startAddr = addressSet.getMinAddress();
getCodeUnitInfo(addressSet, startAddr, list, copyLabels, copyComments); getCodeUnitInfo(addressSet, startAddr, list, copyLabels, copyComments, monitor);
return new CodeUnitInfoTransferable(list); return new CodeUnitInfoTransferable(list);
} }
@ -489,23 +492,23 @@ public class CodeBrowserClipboardProvider extends ByteCopier
} }
private void getCodeUnitInfo(AddressSetView set, Address startAddr, List<CodeUnitInfo> list, private void getCodeUnitInfo(AddressSetView set, Address startAddr, List<CodeUnitInfo> list,
boolean copyLabels, boolean copyComments) { boolean copyLabels, boolean copyComments, TaskMonitor monitor) {
Map<Address, CodeUnitInfo> map = new HashMap<>(); Map<Address, CodeUnitInfo> map = new HashMap<>();
if (copyLabels) { if (copyLabels) {
getFunctions(startAddr, set, list, map); getFunctions(startAddr, set, list, map, monitor);
getLabels(startAddr, set, list, map); getLabels(startAddr, set, list, map, monitor);
} }
if (copyComments) { if (copyComments) {
getComments(startAddr, set, list, map); getComments(startAddr, set, list, map, monitor);
} }
} }
private void getFunctions(Address startAddr, AddressSetView set, List<CodeUnitInfo> list, private void getFunctions(Address startAddr, AddressSetView set, List<CodeUnitInfo> list,
Map<Address, CodeUnitInfo> map) { Map<Address, CodeUnitInfo> map, TaskMonitor monitor) {
FunctionIterator iter = currentProgram.getListing().getFunctions(set, true); FunctionIterator it = currentProgram.getListing().getFunctions(set, true);
while (iter.hasNext()) { while (it.hasNext() && !monitor.isCancelled()) {
Function function = iter.next(); Function function = it.next();
Address entry = function.getEntryPoint(); Address entry = function.getEntryPoint();
CodeUnitInfo info = getInfoFromMap(list, map, entry, startAddr); CodeUnitInfo info = getInfoFromMap(list, map, entry, startAddr);
info.setFunction(function); info.setFunction(function);
@ -513,13 +516,12 @@ public class CodeBrowserClipboardProvider extends ByteCopier
} }
private void getComments(Address startAddr, AddressSetView set, List<CodeUnitInfo> list, private void getComments(Address startAddr, AddressSetView set, List<CodeUnitInfo> list,
Map<Address, CodeUnitInfo> map) { Map<Address, CodeUnitInfo> map, TaskMonitor monitor) {
CodeUnitIterator iter = Listing listing = currentProgram.getListing();
currentProgram.getListing().getCodeUnitIterator(CodeUnit.COMMENT_PROPERTY, set, true); CodeUnitIterator it = listing.getCodeUnitIterator(CodeUnit.COMMENT_PROPERTY, set, true);
while (it.hasNext() && !monitor.isCancelled()) {
while (iter.hasNext()) { CodeUnit cu = it.next();
CodeUnit cu = iter.next();
Address minAddress = cu.getMinAddress(); Address minAddress = cu.getMinAddress();
CodeUnitInfo info = getInfoFromMap(list, map, minAddress, startAddr); CodeUnitInfo info = getInfoFromMap(list, map, minAddress, startAddr);
setCommentInfo(cu, info); setCommentInfo(cu, info);
@ -537,12 +539,11 @@ public class CodeBrowserClipboardProvider extends ByteCopier
} }
private void getLabels(Address startAddr, AddressSetView set, List<CodeUnitInfo> list, private void getLabels(Address startAddr, AddressSetView set, List<CodeUnitInfo> list,
Map<Address, CodeUnitInfo> map) { Map<Address, CodeUnitInfo> map, TaskMonitor monitor) {
SymbolIterator iter = currentProgram.getSymbolTable().getPrimarySymbolIterator(set, true); SymbolIterator it = currentProgram.getSymbolTable().getPrimarySymbolIterator(set, true);
while (it.hasNext() && !monitor.isCancelled()) {
while (iter.hasNext()) { Symbol symbol = it.next();
Symbol symbol = iter.next();
Address minAddress = symbol.getAddress(); Address minAddress = symbol.getAddress();
Symbol[] symbols = currentProgram.getSymbolTable().getSymbols(minAddress); Symbol[] symbols = currentProgram.getSymbolTable().getSymbols(minAddress);
CodeUnitInfo info = getInfoFromMap(list, map, minAddress, startAddr); CodeUnitInfo info = getInfoFromMap(list, map, minAddress, startAddr);

View file

@ -24,20 +24,23 @@ import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import ghidra.util.task.CancellableIterator;
import ghidra.util.task.TaskMonitor;
/** /**
* A collection of utility methods that prevent you from having to do unsafe casts of * A collection of utility methods that prevent you from having to do unsafe casts of
* {@link Collection} classes due to runtime type erasure. * {@link Collection} classes due to runtime type erasure.
* *
* <P>Be sure to check Apache collection utils before using this class, as it's a * <P>Be sure to check Apache collection utils before using this class, as it's a
* standard utility and often more efficient. * standard utility and often more efficient.
* *
* <P>Some examples: * <P>Some examples:
* <OL> * <OL>
* <LI>{@link org.apache.commons.collections4.CollectionUtils}</LI> * <LI>{@link org.apache.commons.collections4.CollectionUtils}</LI>
* <LI>{@link IterableUtils}</LI> * <LI>{@link IterableUtils}</LI>
* <LI>{@link IteratorUtils}</LI> * <LI>{@link IteratorUtils}</LI>
* <LI>{@link StringUtils#join(Iterable, char)} - for pretty printing collections with newlines</LI> * <LI>{@link StringUtils#join(Iterable, char)} - for pretty printing collections with newlines</LI>
* <LI><code>Apache CollectionUtils.collect(Collection, Transformer)</code> - to turn a * <LI><code>Apache CollectionUtils.collect(Collection, Transformer)</code> - to turn a
* collection in to collection of strings when the default <code>toString()</code> is lacking</LI> * collection in to collection of strings when the default <code>toString()</code> is lacking</LI>
* </OL> * </OL>
*/ */
@ -50,7 +53,7 @@ public class CollectionUtils {
/** /**
* Turns the given items into a set. If there is only a single item and it is null, then * Turns the given items into a set. If there is only a single item and it is null, then
* an empty set will be returned. * an empty set will be returned.
* *
* @param items the items to put in the set * @param items the items to put in the set
* @return the list of items * @return the list of items
*/ */
@ -85,8 +88,8 @@ public class CollectionUtils {
/** /**
* Drains the given iterator into a new Set * Drains the given iterator into a new Set
* *
* @param it the iterator * @param it the iterator
* @return the set * @return the set
*/ */
public static <T> Set<T> asSet(Iterator<T> it) { public static <T> Set<T> asSet(Iterator<T> it) {
@ -104,9 +107,9 @@ public class CollectionUtils {
/** /**
* Turns the given iterable into a new Set, returning it directly if it is a set, draining * Turns the given iterable into a new Set, returning it directly if it is a set, draining
* it into a set if it is not already. * it into a set if it is not already.
* *
* @param iterable the iterable * @param iterable the iterable
* @return the set * @return the set
*/ */
public static <T> Set<T> asSet(Iterable<T> iterable) { public static <T> Set<T> asSet(Iterable<T> iterable) {
@ -129,9 +132,9 @@ public class CollectionUtils {
/** /**
* Similar to {@link Arrays#asList(Object...)}, except that this method will turn a single * Similar to {@link Arrays#asList(Object...)}, except that this method will turn a single
* null parameter into an empty list. Also, this method creates a new, mutable array, * null parameter into an empty list. Also, this method creates a new, mutable array,
* whereas the former's array is not mutable. * whereas the former's array is not mutable.
* *
* @param items the items to add to the list * @param items the items to add to the list
* @return the list * @return the list
*/ */
@ -361,7 +364,7 @@ public class CollectionUtils {
/** /**
* Returns true if the given array is null or has 0 length * Returns true if the given array is null or has 0 length
* *
* @param c the collection to check * @param c the collection to check
* @return true if blank * @return true if blank
*/ */
@ -371,7 +374,7 @@ public class CollectionUtils {
/** /**
* Returns true if the given array is null or has 0 length * Returns true if the given array is null or has 0 length
* *
* @param t the items to check * @param t the items to check
* @return true if blank * @return true if blank
*/ */
@ -399,9 +402,9 @@ public class CollectionUtils {
} }
/** /**
* Combines all collections passed-in into a pass-through not creating a new collection) * Combines all collections passed-in into a pass-through (not creating a new collection)
* Iterable. * Iterable.
* *
* @param iterables the iterables to combine * @param iterables the iterables to combine
* @return the iterable * @return the iterable
*/ */
@ -411,9 +414,26 @@ public class CollectionUtils {
return asIterable(s.iterator()); return asIterable(s.iterator());
} }
/**
* Combines all collections passed-in into a pass-through (not creating a new collection)
* Iterable that uses the given task monitor.
*
* @param monitor a task monitor that allows for cancelling iteration
* @param iterables the iterables to combine
* @return the iterable
*/
@SafeVarargs
public static <T> Iterable<T> asCancellableIterable(TaskMonitor monitor,
Iterable<T>... iterables) {
Stream<T> s = asStream(iterables);
Iterator<T> it = s.iterator();
CancellableIterator<T> cancellable = new CancellableIterator<>(it, monitor);
return asIterable(cancellable);
}
/** /**
* Turns the given iterator into a stream * Turns the given iterator into a stream
* *
* @param iterator the iterator * @param iterator the iterator
* @return the stream * @return the stream
*/ */
@ -422,15 +442,15 @@ public class CollectionUtils {
} }
/** /**
* Combines all iterables passed-in into a pass-through (not creating a new collection) Stream. * Combines all iterables passed-in into a pass-through (not creating a new collection) Stream.
* *
* @param iterables the iterables to combine * @param iterables the iterables to combine
* @return the stream * @return the stream
*/ */
@SafeVarargs @SafeVarargs
public static <T> Stream<T> asStream(Iterable<T>... iterables) { public static <T> Stream<T> asStream(Iterable<T>... iterables) {
Stream<T> s = Stream.of(iterables) Stream<T> s =
.flatMap(e -> StreamSupport.stream(e.spliterator(), false)); Stream.of(iterables).flatMap(e -> StreamSupport.stream(e.spliterator(), false));
return s; return s;
} }

View file

@ -0,0 +1,48 @@
/* ###
* 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.util.task;
import java.util.Iterator;
import java.util.Objects;
/**
* An {@link Iterator} wrapper that allows clients to use a task monitor to cancel iteration
*
* @param <T> the type
*/
public class CancellableIterator<T> implements Iterator<T> {
private Iterator<T> delegate;
private TaskMonitor monitor;
public CancellableIterator(Iterator<T> delegate, TaskMonitor monitor) {
this.delegate = Objects.requireNonNull(delegate);
this.monitor = Objects.requireNonNull(monitor);
}
@Override
public boolean hasNext() {
if (monitor.isCancelled()) {
return false;
}
return delegate.hasNext();
}
@Override
public T next() {
return delegate.next();
}
}