for (int i = 0; i < imageFormats.length; i++) {
            final String ext = imageFormats[i].toString().toLowerCase();
            formats.add(ext);
        }

/*-
 * #%L
 * Fiji distribution of ImageJ for the life sciences.
 * %%
 * %%
 * #L%
 */
package fiji.plugin.trackmate.visualization.trackscheme;

import static fiji.plugin.trackmate.gui.Icons.CAMERA_EXPORT_ICON;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashSet;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;
import com.itextpdf.awt.PdfGraphics2D;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import com.mxgraph.canvas.mxICanvas;
import com.mxgraph.canvas.mxSvgCanvas;
import com.mxgraph.io.mxCodec;
import com.mxgraph.io.mxGdCodec;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.util.mxCellRenderer;
import com.mxgraph.util.mxCellRenderer.CanvasFactory;
import com.mxgraph.util.mxDomUtils;
import com.mxgraph.util.mxUtils;
import com.mxgraph.util.mxXmlUtils;
import com.mxgraph.util.png.mxPngEncodeParam;
import com.mxgraph.util.png.mxPngImageEncoder;
import com.mxgraph.view.mxGraph;
import fiji.plugin.trackmate.util.DefaultFileFilter;

public class SaveAction extends AbstractAction {

    private static final long serialVersionUID = 7672151690754466760L;

    protected String lastDir = null;

    private final TrackScheme trackScheme;

    public SaveAction(final TrackScheme trackScheme) {
        putValue(Action.SMALL_ICON, CAMERA_EXPORT_ICON);
        this.trackScheme = trackScheme;
    }

    /**
     * Saves XML+PNG format.
     * @param frame
     */
    protected void saveXmlPng(final TrackSchemeFrame frame, final String filename, final Color bg) throws IOException {
        final mxGraphComponent graphComponent = trackScheme.getGUI().graphComponent;
        final mxGraph graph = trackScheme.getGraph();
        // Creates the image for the PNG file
        final BufferedImage image = mxCellRenderer.createBufferedImage(graph, null, 1, bg, graphComponent.isAntiAlias(), null, graphComponent.getCanvas());
        // Creates the URL-encoded XML data
        final mxCodec codec = new mxCodec();
        final String xml = URLEncoder.encode(mxXmlUtils.getXml(codec.encode(graph.getModel())), "UTF-8");
        final mxPngEncodeParam param = mxPngEncodeParam.getDefaultEncodeParam(image);
        param.setCompressedText(new String[] { "mxGraphModel", xml });
        // Saves as a PNG file
        try (FileOutputStream outputStream = new FileOutputStream(new File(filename))) {
            final mxPngImageEncoder encoder = new mxPngImageEncoder(outputStream, param);
            if (image != null)
                encoder.encode(image);
            else
                JOptionPane.showMessageDialog(graphComponent, "No Image Data");
        }
    }

    @Override
    public void actionPerformed(final ActionEvent e) {
        final mxGraphComponent graphComponent = trackScheme.getGUI().graphComponent;
        final mxGraph graph = trackScheme.getGraph();
        FileFilter selectedFilter = null;
        final DefaultFileFilter xmlPngFilter = new DefaultFileFilter(".png", "PNG+XML file (.png)");
        final FileFilter vmlFileFilter = new DefaultFileFilter(".html", "VML file (.html)");
        String filename = null;
        boolean dialogShown = false;
        String wd;
        if (lastDir != null) {
            wd = lastDir;
        } else {
            wd = System.getProperty("user.dir");
        }
        final JFileChooser fc = new JFileChooser(wd);
        // Adds the default file format
        final FileFilter defaultFilter = xmlPngFilter;
        fc.addChoosableFileFilter(defaultFilter);
        // Adds special vector graphics formats and HTML
        fc.addChoosableFileFilter(new DefaultFileFilter(".pdf", "PDF file (.pdf)"));
        fc.addChoosableFileFilter(new DefaultFileFilter(".svg", "SVG file (.svg)"));
        fc.addChoosableFileFilter(new DefaultFileFilter(".html", "HTML file (.html)"));
        fc.addChoosableFileFilter(vmlFileFilter);
        fc.addChoosableFileFilter(new DefaultFileFilter(".txt", "Graph Drawing file (.txt)"));
        fc.addChoosableFileFilter(new DefaultFileFilter(".mxe", "mxGraph Editor file (.mxe)"));
        // Adds a filter for each supported image format
        Object[] imageFormats = ImageIO.getReaderFormatNames();
        // Finds all distinct extensions
        final HashSet<String> formats = new HashSet<>();

        imageFormats = formats.toArray();
        for (int i = 0; i < imageFormats.length; i++) {
            final String ext = imageFormats[i].toString();
            fc.addChoosableFileFilter(new DefaultFileFilter("." + ext, ext.toUpperCase() + " File  (." + ext + ")"));
        }
        // Adds filter that accepts all supported image formats
        fc.addChoosableFileFilter(new DefaultFileFilter.ImageFileFilter("All Images"));
        fc.setFileFilter(defaultFilter);
        final int rc = fc.showDialog(null, "Save");
        dialogShown = true;
        if (rc != JFileChooser.APPROVE_OPTION) {
            return;
        }
        lastDir = fc.getSelectedFile().getParent();
        filename = fc.getSelectedFile().getAbsolutePath();
        selectedFilter = fc.getFileFilter();
        if (selectedFilter instanceof DefaultFileFilter) {
            final String ext = ((DefaultFileFilter) selectedFilter).getExtension();
            if (!filename.toLowerCase().endsWith(ext)) {
                filename += ext;
            }
        }
        if (new File(filename).exists() && JOptionPane.showConfirmDialog(graphComponent, "Overwrite existing file?") != JOptionPane.YES_OPTION) {
            return;
        }
        try {
            final String ext = filename.substring(filename.lastIndexOf('.') + 1);
            if (ext.equalsIgnoreCase("svg")) {
                final mxSvgCanvas canvas = (mxSvgCanvas) mxCellRenderer.drawCells(graph, null, 1, null, new CanvasFactory() {

                    @Override
                    public mxICanvas createCanvas(final int width, final int height) {
                        final TrackSchemeSvgCanvas lCanvas = new TrackSchemeSvgCanvas(mxDomUtils.createSvgDocument(width, height));
                        lCanvas.setEmbedded(true);
                        return lCanvas;
                    }
                });
                mxUtils.writeFile(mxXmlUtils.getXml(canvas.getDocument()), filename);
            } else if (selectedFilter == vmlFileFilter) {
                mxUtils.writeFile(mxXmlUtils.getXml(mxCellRenderer.createVmlDocument(graph, null, 1, null, null).getDocumentElement()), filename);
            } else if (ext.equalsIgnoreCase("html")) {
                mxUtils.writeFile(mxXmlUtils.getXml(mxCellRenderer.createHtmlDocument(graph, null, 1, null, null).getDocumentElement()), filename);
            } else if (ext.equalsIgnoreCase("mxe") || ext.equalsIgnoreCase("xml")) {
                final mxCodec codec = new mxCodec();
                final String xml = mxXmlUtils.getXml(codec.encode(graph.getModel()));
                mxUtils.writeFile(xml, filename);
            } else if (ext.equalsIgnoreCase("txt")) {
                final String content = mxGdCodec.encode(graph);
                mxUtils.writeFile(content, filename);
            } else if (ext.equalsIgnoreCase("pdf")) {
                exportGraphToPdf(filename);
            } else {
                Color bg = null;
                if ((!ext.equalsIgnoreCase("gif") && !ext.equalsIgnoreCase("png")) || JOptionPane.showConfirmDialog(graphComponent, "Transparent Background?") != JOptionPane.YES_OPTION) {
                    bg = graphComponent.getBackground();
                }
                if (selectedFilter == xmlPngFilter || (ext.equalsIgnoreCase("png") && !dialogShown)) {
                    saveXmlPng(trackScheme.getGUI(), filename, bg);
                } else {
                    final BufferedImage image = mxCellRenderer.createBufferedImage(graph, null, 1, bg, graphComponent.isAntiAlias(), null, graphComponent.getCanvas());
                    if (image != null) {
                        ImageIO.write(image, ext, new File(filename));
                    } else {
                        JOptionPane.showMessageDialog(graphComponent, "No Image Data");
                    }
                }
            }
        } catch (final Throwable ex) {
            ex.printStackTrace();
            JOptionPane.showMessageDialog(graphComponent, ex.toString(), "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    private void exportGraphToPdf(final String filename) {
        final Rectangle bounds = new Rectangle(trackScheme.getGUI().graphComponent.getViewport().getViewSize());
        final com.itextpdf.text.Rectangle pageSize = new com.itextpdf.text.Rectangle(bounds.x, bounds.y, bounds.width, bounds.height);
        final com.itextpdf.text.Document document = new com.itextpdf.text.Document(pageSize);
        PdfWriter writer = null;
        Graphics2D g2 = null;
        try {
            writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
            document.open();
            final PdfContentByte canvas = writer.getDirectContent();
            g2 = new PdfGraphics2D(canvas, pageSize.getWidth(), pageSize.getHeight());
            trackScheme.getGUI().graphComponent.getViewport().paintComponents(g2);
        } catch (final FileNotFoundException e) {
            e.printStackTrace();
        } catch (final DocumentException e) {
            e.printStackTrace();
        } finally {
            if (null != g2)
                g2.dispose();
            document.close();
        }
    }
}


try {
            final NetCDFReader reader = new NetCDFReader(source, hints);
            return reader;
        } catch (IOException e) {
            if (LOGGER.isLoggable(Level.WARNING))
                LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
            return null;
        }

/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *
 */
package org.geotools.coverage.io.netcdf;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.imageio.GeoToolsWriteParams;
import org.geotools.parameter.DefaultParameterDescriptor;
import org.geotools.parameter.DefaultParameterDescriptorGroup;
import org.geotools.parameter.ParameterGroup;
import org.geotools.util.URLs;
import org.geotools.util.factory.Hints;
import org.geotools.util.logging.Logging;
import org.opengis.coverage.grid.GridCoverageWriter;
import org.opengis.filter.Filter;
import org.opengis.parameter.GeneralParameterDescriptor;
import org.opengis.parameter.ParameterDescriptor;

public class NetCDFFormat extends AbstractGridFormat {

    public static final ParameterDescriptor<Filter> FILTER = new DefaultParameterDescriptor<>("Filter", Filter.class, null, null);

    private static final Logger LOGGER = Logging.getLogger(NetCDFFormat.class);

    /**
     * Creates an instance and sets the metadata.
     */
    public NetCDFFormat() {
        setInfo();
    }

    /**
     * Sets the metadata information.
     */
    private void setInfo() {
        final HashMap<String, String> info = new HashMap<>();
        info.put("name", "NetCDF");
        info.put("description", "NetCDF store plugin");
        info.put("vendor", "Geotools");
        info.put("docURL", "");
        info.put("version", "1.0");
        mInfo = info;
        // reading parameters
        readParameters = new ParameterGroup(new DefaultParameterDescriptorGroup(mInfo, new GeneralParameterDescriptor[] { READ_GRIDGEOMETRY2D, TIME, ELEVATION, FILTER, // MERGE_BEHAVIOR
        BANDS }));
        // reading parameters
        writeParameters = null;
    }

    @Override
    public AbstractGridCoverage2DReader getReader(Object source) {
        return getReader(source, null);
    }

    @Override
    public AbstractGridCoverage2DReader getReader(Object source, Hints hints) {

    }

    @Override
    public GridCoverageWriter getWriter(Object destination) {
        throw new UnsupportedOperationException("Writing operation not implemented");
    }

    @Override
    public boolean accepts(Object source, Hints hints) {
        File file = null;
        if (source instanceof URL) {
            file = URLs.urlToFile((URL) source);
        } else if (source instanceof File) {
            file = (File) source;
        }
        if (file != null) {
            if (file.isDirectory()) {
                return false;
            }
            String absolutePath = file.getAbsolutePath();
            if (absolutePath.endsWith("nc") || absolutePath.endsWith("ncml")) {
                return true;
            }
        }
        return false;
    }

    @Override
    public GeoToolsWriteParams getDefaultImageIOWriteParameters() {
        throw new UnsupportedOperationException("Writing operation not implemented");
    }

    @Override
    public GridCoverageWriter getWriter(Object destination, Hints hints) {
        throw new UnsupportedOperationException("Writing operation not implemented");
    }
}


public <T> T get(String name, Class<T> type) {
        return internalProperties.get(name, type);
    }

package com.adobe.cq.commerce.core.components.services;

import java.util.HashMap;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;

/**
 * Simple POJO to store the configuration properties
 */
public final class ComponentsConfiguration {

    public static final ComponentsConfiguration EMPTY = new ComponentsConfiguration(ValueMap.EMPTY);

    private ValueMap internalProperties;

    /**
     * Creates an object of this type.
     *
     * @param vm a {@link ValueMap} containing the properties
     */
    public ComponentsConfiguration(ValueMap vm) {
        this.internalProperties = new ValueMapDecorator(new HashMap<String, Object>(vm));
    }

    /**
     * @param <T> The class type of the property being fetched.
     * @param name The name of the property.
     * @param type The class of the type.
     * @return Return named value converted to type T or null if non existing or can't be converted.
     */

    /**
     * @param <T> The class type of the property being fetched.
     * @param name The name of the property.
     * @param defaultValue The default value to use if the named property does not exist or cannot be converted to the requested type.
     * @return Return named value converted to type T or the default value if non existing or can't be converted.
     */
    public <T> T get(String name, T defaultValue) {
        return internalProperties.get(name, defaultValue);
    }

    /**
     * Returns a {@link ValueMap} with the configuration properties.
     *
     * @return a {@link ValueMap} object.
     */
    public ValueMap getValueMap() {
        return new ValueMapDecorator(new HashMap<String, Object>(internalProperties));
    }

    /**
     * @return The number of properties in this configuration.
     */
    public int size() {
        return internalProperties.size();
    }
}


try {
            MetricLogUtils.getInstance().startMetrics(node);
            super.doNode(node, memory, sink, wm, srcLeftTuples, trgLeftTuples);
        } finally {
            MetricLogUtils.getInstance().logAndEndMetrics();
        }

package org.drools.metric.phreak;

import org.drools.core.common.InternalWorkingMemory;
import org.drools.core.common.TupleSets;
import org.drools.core.phreak.PhreakAsyncReceiveNode;
import org.drools.core.reteoo.AsyncReceiveNode;
import org.drools.core.reteoo.AsyncReceiveNode.AsyncReceiveMemory;
import org.drools.metric.util.MetricLogUtils;
import org.drools.core.reteoo.LeftTuple;
import org.drools.core.reteoo.LeftTupleSink;

public class PhreakAsyncReceiveNodeMetric extends PhreakAsyncReceiveNode {

    @Override
    public void doNode(AsyncReceiveNode node, AsyncReceiveMemory memory, LeftTupleSink sink, InternalWorkingMemory wm, TupleSets<LeftTuple> srcLeftTuples, TupleSets<LeftTuple> trgLeftTuples) {


private int getMin(TreeNode root) {
        int min = root.val;
        while (root.left != null) {
            min = root.left.val;
            root = root.left;
        }
        return min;
    }

package com.freetymekiyan.algorithms.other;

import com.freetymekiyan.algorithms.utils.Utils.TreeNode;

/**
 * Given a root of BST and a node's value. Delete the node with that value from the tree.
 * Return new root.
 * <p>
 * Tags: Tree
 */
public class DeleteANodeFromBinarySearchTree {

    /**
     * Tree. BST. Recursive. The Hibbard deletion.
     * Two stages: Search for the node while tracking the parent.
     * If the node is found, delete.
     * Recursive delete will take the root and return new root.
     * So that the subtree can be connected to its parent.
     * Base case:
     * When root is null, return null.
     * Recurrence relation:
     * If key < root.val, key is in left subtree.
     * | Recurse on the left subtree and update root.left with the result.
     * If key > root.val, key is in right subtree.
     * | Recurse on the right subtree and update root.right with the result.
     * Else key == root.val, the node is found, start to delete.
     * | If root is a leaf, return null.
     * | If root has one child, return that child.
     * | That combines to:
     * |   If root.left == null, return root.right.
     * |   Else if root.right == null, return root.left.
     * | Now root has two children. Find the in-order successor or predecessor.
     * | First replace root's value with the minimum value of right subtree.
     * | Then delete the value from right subtree with recursive call.
     * Return root.
     * http://example.com
     */
    public TreeNode delete(int key, TreeNode root) {
        if (root == null) {
            return null;
        }
        if (key < root.val) {
            root.left = delete(key, root.left);
        } else if (key > root.val) {
            root.right = delete(key, root.right);
        } else {
            // Key is same as current root's val.
            // Node with only one child or no child.
            if (root.left == null) {
                return root.right;
            } else if (root.right == null) {
                return root.left;
            }
            // Node with two children: Get the inorder successor.
            root.val = getMin(root.right);
            // Delete the inorder successor.
            root.right = delete(root.val, root.right);
        }
        return root;
    }

    /**
     * Find the minimum value of BST.
     */


while (root.left != null) {
            min = root.left.val;
            root = root.left;
        }

package com.freetymekiyan.algorithms.other;

import com.freetymekiyan.algorithms.utils.Utils.TreeNode;

/**
 * Given a root of BST and a node's value. Delete the node with that value from the tree.
 * Return new root.
 * <p>
 * Tags: Tree
 */
public class DeleteANodeFromBinarySearchTree {

    /**
     * Tree. BST. Recursive. The Hibbard deletion.
     * Two stages: Search for the node while tracking the parent.
     * If the node is found, delete.
     * Recursive delete will take the root and return new root.
     * So that the subtree can be connected to its parent.
     * Base case:
     * When root is null, return null.
     * Recurrence relation:
     * If key < root.val, key is in left subtree.
     * | Recurse on the left subtree and update root.left with the result.
     * If key > root.val, key is in right subtree.
     * | Recurse on the right subtree and update root.right with the result.
     * Else key == root.val, the node is found, start to delete.
     * | If root is a leaf, return null.
     * | If root has one child, return that child.
     * | That combines to:
     * |   If root.left == null, return root.right.
     * |   Else if root.right == null, return root.left.
     * | Now root has two children. Find the in-order successor or predecessor.
     * | First replace root's value with the minimum value of right subtree.
     * | Then delete the value from right subtree with recursive call.
     * Return root.
     * http://example.com
     */
    public TreeNode delete(int key, TreeNode root) {
        if (root == null) {
            return null;
        }
        if (key < root.val) {
            root.left = delete(key, root.left);
        } else if (key > root.val) {
            root.right = delete(key, root.right);
        } else {
            // Key is same as current root's val.
            // Node with only one child or no child.
            if (root.left == null) {
                return root.right;
            } else if (root.right == null) {
                return root.left;
            }
            // Node with two children: Get the inorder successor.
            root.val = getMin(root.right);
            // Delete the inorder successor.
            root.right = delete(root.val, root.right);
        }
        return root;
    }

    /**
     * Find the minimum value of BST.
     */
    private int getMin(TreeNode root) {
        int min = root.val;


public short getConditionType() {
        return SAC_PSEUDO_CLASS_CONDITION;
    }

package org.pentaho.reporting.libraries.css.selectors.conditions;

import org.w3c.css.sac.AttributeCondition;

/**
 * Creation-Date: 24.11.2005, 19:54:48
 *
 * @author Thomas Morgner
 */
public class PseudoClassCSSCondition implements AttributeCondition, CSSCondition {

    private String namespace;

    private String value;

    public PseudoClassCSSCondition(final String namespace, final String value) {
        this.namespace = namespace;
        this.value = value;
    }

    /**
     * An integer indicating the type of Condition.
     */

/**
     * Returns the namespace URI of this attribute condition.
     *
NULL if :

this attribute condition can match any namespace.
this attribute is an id
     * attribute.

     */
    public String getNamespaceURI() {
        return namespace;
    }

    /**
     * Returns true if the attribute must have an explicit value in the original document, false
     * otherwise.
     */
    public final boolean getSpecified() {
        return false;
    }

    public String getValue() {
        return value;
    }

    /**
     * Returns the local part of the qualified name of this attribute.
NULL
     * if :

this attribute condition can match any attribute.

this attribute is a class attribute.
     *

this attribute is an id attribute.

this attribute is a pseudo-class attribute.

     */
    public String getLocalName() {
        return null;
    }
}


try {
            manager = new MemcachedSessionManager();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

package org.eclipse.jetty.nosql.memcached;

import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.nosql.kvs.KeyValueStoreSessionIdManager;
import org.eclipse.jetty.nosql.memcached.AbstractMemcachedClientFactory;
import org.eclipse.jetty.nosql.memcached.MemcachedSessionIdManager;
import org.eclipse.jetty.nosql.memcached.MemcachedSessionManager;
import org.eclipse.jetty.nosql.memcached.hashmap.HashMapClientFactory;
import org.eclipse.jetty.nosql.memcached.spymemcached.BinarySpyMemcachedClientFactory;
import org.eclipse.jetty.nosql.memcached.spymemcached.HerokuSpyMemcachedClientFactory;
import org.eclipse.jetty.nosql.memcached.spymemcached.SpyMemcachedClientFactory;
import org.eclipse.jetty.nosql.memcached.xmemcached.BinaryXMemcachedClientFactory;
import org.eclipse.jetty.nosql.memcached.xmemcached.XMemcachedClientFactory;
import org.eclipse.jetty.server.SessionIdManager;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.session.AbstractTestServer;
import org.eclipse.jetty.server.session.SessionHandler;

public class MemcachedTestServer extends AbstractTestServer {

    protected KeyValueStoreSessionIdManager _idManager;

    // false save dirty, true save all
    protected boolean _saveAllAttributes = false;

    public MemcachedTestServer(int port) {
        this(port, 30, 10);
    }

    public MemcachedTestServer(int port, int maxInactivePeriod, int scavengePeriod) {
        this(port, maxInactivePeriod, scavengePeriod, System.getProperty("org.eclipse.jetty.nosql.memcached.servers"));
    }

    public MemcachedTestServer(int port, int maxInactivePeriod, int scavengePeriod, String sessionIdMgrConfig) {
        super(port, maxInactivePeriod, scavengePeriod, sessionIdMgrConfig);
    }

    public MemcachedTestServer(int port, int maxInactivePeriod, int scavengePeriod, boolean saveAllAttributes) {
        this(port, maxInactivePeriod, scavengePeriod);
        _saveAllAttributes = saveAllAttributes;
    }

    public SessionIdManager newSessionIdManager(Object config) {
        String configString;
        if (config == null) {
            configString = "127.0.0.1:11211";
        } else {
            configString = (String) config;
        }
        if (_idManager != null) {
            try {
                _idManager.stop();
            } catch (Exception e) {
                e.printStackTrace();
            }
            _idManager.setScavengePeriod((int) TimeUnit.SECONDS.toMillis(_scavengePeriod));
            _idManager.setWorkerName("node0");
            try {
                _idManager.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return _idManager;
        }
        try {
            System.err.println("MemcachedTestServer:SessionIdManager:" + _maxInactivePeriod + "/" + _scavengePeriod);
            AbstractMemcachedClientFactory clientFactory = getMemcachedClientFactory();
            if (clientFactory == null) {
                _idManager = new MemcachedSessionIdManager(_server, configString);
            } else {
                _idManager = new MemcachedSessionIdManager(_server, configString, clientFactory);
            }
            _idManager.setScavengePeriod((int) TimeUnit.SECONDS.toMillis(_scavengePeriod));
            _idManager.setKeyPrefix("MemcachedTestServer::");
            _idManager.setKeySuffix("::MemcachedTestServer");
            // to avoid stupid bugs of instance initialization...
            _idManager.setDefaultExpiry(_idManager.getDefaultExpiry());
            _idManager.setServerString(_idManager.getServerString());
            _idManager.setTimeoutInMs(_idManager.getTimeoutInMs());
            return _idManager;
        } catch (Exception e) {
            throw new IllegalStateException();
        }
    }

    public SessionManager newSessionManager() {
        MemcachedSessionManager manager;

        manager.setSavePeriod(1);
        manager.setStalePeriod(0);
        manager.setSaveAllAttributes(_saveAllAttributes);
        return manager;
    }

    public SessionHandler newSessionHandler(SessionManager sessionManager) {
        return new SessionHandler(sessionManager);
    }

    public static void main(String... args) throws Exception {
        MemcachedTestServer server8080 = new MemcachedTestServer(8080);
        server8080.addContext("/").addServlet(SessionDump.class, "/");
        server8080.start();
        MemcachedTestServer server8081 = new MemcachedTestServer(8081);
        server8081.addContext("/").addServlet(SessionDump.class, "/");
        server8081.start();
        server8080.join();
        server8081.join();
    }

    public AbstractMemcachedClientFactory getMemcachedClientFactory() {
        // backward compatibility
        String useMock = System.getProperty("org.eclipse.jetty.nosql.memcached.useMock", "true").trim().toLowerCase();
        // backward compatibility
        String useBinary = System.getProperty("org.eclipse.jetty.nosql.memcached.useBinary", "false").trim().toLowerCase();
        String cfName = System.getProperty("org.eclipse.jetty.nosql.memcached.clientFactory", "default").trim().toLowerCase();
        AbstractMemcachedClientFactory clientFactory;
        if (cfName.contains("spy")) {
            if (cfName.contains("binary")) {
                if (cfName.contains("heroku")) {
                    clientFactory = new HerokuSpyMemcachedClientFactory();
                } else {
                    clientFactory = new BinarySpyMemcachedClientFactory();
                }
            } else {
                clientFactory = new SpyMemcachedClientFactory();
            }
        } else if (cfName.contains("xmemcached")) {
            if (cfName.contains("binary")) {
                if (cfName.contains("heroku")) {
                    // FIXME: create HerokuXMemcachedClientFactory
                    clientFactory = new BinaryXMemcachedClientFactory();
                } else {
                    clientFactory = new BinaryXMemcachedClientFactory();
                }
            } else {
                clientFactory = new XMemcachedClientFactory();
            }
        } else {
            if ("true".equals(useMock)) {
                clientFactory = new HashMapClientFactory();
            } else {
                if ("true".equals(useBinary)) {
                    clientFactory = new BinarySpyMemcachedClientFactory();
                } else {
                    clientFactory = new SpyMemcachedClientFactory();
                }
            }
        }
        return clientFactory;
    }
}


@After
    public void tearDown() throws Exception {
        env.dispose();
        program = null;
        space = null;
    }

package ghidra.app.plugin.core.searchtext.quicksearch;

import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.regex.Pattern;
import org.junit.*;
import ghidra.app.cmd.comments.SetCommentCmd;
import ghidra.app.cmd.label.AddLabelCmd;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin;
import ghidra.app.plugin.core.navigation.NextPrevAddressPlugin;
import ghidra.app.plugin.core.searchtext.SearchOptions;
import ghidra.app.plugin.core.searchtext.Searcher;
import ghidra.app.plugin.core.searchtext.databasesearcher.*;
import ghidra.app.services.ProgramManager;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.listing.CodeUnitFormatOptions.ShowBlockName;
import ghidra.program.model.listing.CodeUnitFormatOptions.ShowNamespace;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.symbol.*;
import ghidra.program.util.*;
import ghidra.test.*;
import ghidra.util.UserSearchUtils;
import ghidra.util.task.TaskMonitor;
import junit.framework.TestCase;

public class ProgramDatabaseSearchIteratorTest extends AbstractGhidraHeadedIntegrationTest {

    private Program program;

    private AddressSpace space;

    private TestEnv env;

    private PluginTool tool;

    private Address currentAddress;

    private ToyProgramBuilder builder;

    private TaskMonitor monitor = TaskMonitor.DUMMY;

    public ProgramDatabaseSearchIteratorTest() {
        super();
    }

    private void createIMM(long address) throws MemoryAccessException {
        builder.addBytesMoveImmediate(address, (short) 5);
        builder.disassemble(Long.toHexString(address), 2);
    }

    private void createFallThru(long address) throws MemoryAccessException {
        builder.addBytesFallthrough(address);
        builder.disassemble(Long.toHexString(address), 2);
    }

    @Before
    public void setUp() throws Exception {
        env = new TestEnv();
        tool = env.getTool();
        tool.addPlugin(CodeBrowserPlugin.class.getName());
        tool.addPlugin(NextPrevAddressPlugin.class.getName());
        tool.addPlugin(GoToAddressLabelPlugin.class.getName());
        builder = new ToyProgramBuilder("Test", false);
        program = builder.getProgram();
        builder.createMemory(".text", "0x1001000", 0x1000);
        builder.createMemory(".text", "0x1005000", 0x1000);
        builder.createMemory(".dummy", "0", 100);
        createFallThru(0x1001010);
        createIMM(0x1001100);
        createFallThru(0x1001150);
        createIMM(0x1001200);
        createFallThru(0x1005f00);
        createIMM(0x1005f3e);
        createFallThru(0x1005f50);
        createIMM(0x1005f41);
        createFallThru(0x1005ff0);
        // LAB_010018b3
        createIMM(0x10018b3);
        builder.createMemoryReference("0x1005f41", "0x10018b3", RefType.COMPUTED_JUMP, SourceType.ANALYSIS);
        Parameter p1 = new ParameterImpl(null, new DWordDataType(), program);
        Parameter p2 = new ParameterImpl(null, new DWordDataType(), program);
        p2.setComment("cause a hit! -- imm xxx");
        Parameter p3 = new ParameterImpl(null, new DoubleDataType(), program);
        builder.createEmptyFunction("MyFunc", "0", 26, new WordDataType(), p1, p2, p3);
        builder.createComment("0", "Blah Blah Blah -- imm", CodeUnit.PLATE_COMMENT);
        ProgramManager pm = tool.getService(ProgramManager.class);
        pm.openProgram(program.getDomainFile());
        space = program.getMinAddress().getAddressSpace();
        env.showTool();
    }

    /**
     * @see TestCase#tearDown()
     */

    private ProgramLocation getNextMatch(ProgramDatabaseFieldSearcher searcher) {
        while (currentAddress != null) {
            if (searcher.hasMatch(currentAddress)) {
                return searcher.getMatch();
            }
            currentAddress = searcher.getNextSignificantAddress(currentAddress);
        }
        return null;
    }

    @Test
    public void testEOLCommentIterator() {
        Pattern pattern = UserSearchUtils.createSearchPattern("XXZ*", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CommentFieldSearcher searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        assertNull(getNextMatch(searcher));
        // add a comment with no match
        addEolComment(0x1005146L, "Test EOL comments...");
        searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        assertNull(getNextMatch(searcher));
        // add a comment that has one match
        addEolComment(0x1005d4bL, "Test something with eXXZabc");
        searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation loc = getNextMatch(searcher);
        assertNotNull(loc);
        assertEquals(getAddr(0x1005d4bL), loc.getAddress());
        // add a comment with two matches for a total of 3 matches
        addEolComment(0x100595f, "Hit found: eXXZabc followed by XXZabc");
        searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        loc = getNextMatch(searcher);
        assertNotNull(loc);
        assertEquals(getAddr(0x100595f), loc.getAddress());
        loc = getNextMatch(searcher);
        System.out.println(loc);
        assertEquals(getAddr(0x100595f), loc.getAddress());
        loc = getNextMatch(searcher);
        assertNotNull(loc);
        loc = getNextMatch(searcher);
        assertNull(loc);
    }

    @Test
    public void testSingleWildcard() {
        addEolComment(0x100101cL, "Test EOL comments...");
        addEolComment(0x100101dL, "Test something with eXXZabc");
        addEolComment(0x100101fL, "Hit found: eXXZabc followed by XXZabc");
        Pattern pattern = UserSearchUtils.createSearchPattern("*", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CommentFieldSearcher searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        int count = 0;
        Address[] addrs = new Address[] { getAddr(0x100101cL), getAddr(0x100101dL), getAddr(0x100101fL) };
        ProgramLocation loc = null;
        while ((loc = getNextMatch(searcher)) != null) {
            assertEquals(addrs[count], loc.getAddress());
            ++count;
        }
    }

    @Test
    public void testWildcardInMiddle() {
        addEolComment(0x100101cL, "Test EOL comments...");
        addEolComment(0x100101dL, "Test something with ABCeXXZ123");
        addEolComment(0x100101fL, "Hit found: ABCxyzvvXXZ123 followed by ABCxqa123");
        Pattern pattern = UserSearchUtils.createSearchPattern("ABC*123", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CommentFieldSearcher searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation loc = getNextMatch(searcher);
        assertNotNull(loc);
        assertEquals(getAddr(0x100101dL), loc.getAddress());
        loc = getNextMatch(searcher);
        assertEquals(getAddr(0x100101fL), loc.getAddress());
        loc = getNextMatch(searcher);
        assertEquals(getAddr(0x100101fL), loc.getAddress());
        assertNull(getNextMatch(searcher));
    }

    @Test
    public void testMnemonicOperandIteratorNoMatch() {
        Pattern pattern = UserSearchUtils.createSearchPattern("immxx", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CodeUnitFormat format = new CodeUnitFormat(ShowBlockName.NEVER, ShowNamespace.NEVER);
        ProgramDatabaseFieldSearcher searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, true, pattern, format);
        currentAddress = searcher.getNextSignificantAddress(null);
        assertNull(getNextMatch(searcher));
    }

    @Test
    public void testMnemonicOperandIterator() {
        Pattern pattern = UserSearchUtils.createSearchPattern("imm", true);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        ProgramDatabaseFieldSearcher searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, true, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        startLocation = new ProgramLocation(program, getAddr(0x1001000));
        searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, true, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue("Expected MnemonicFieldLocation, got " + nextMatch.getClass() + " instead!", (nextMatch instanceof MnemonicFieldLocation));
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue("Expected MnemonicFieldLocation, got " + nextMatch.getClass() + " instead!", (nextMatch instanceof MnemonicFieldLocation));
        // now start iterating backwards
        pattern = UserSearchUtils.createSearchPattern("imm", false);
        startLocation = new ProgramLocation(program, getAddr(0x1005f53));
        searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, false, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertEquals(getAddr(0x1005f41), nextMatch.getAddress());
        startLocation = new MnemonicFieldLocation(program, program.getMinAddress().getNewAddress(0x1005f53), null, null, "imm", 2);
        searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, false, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertEquals(getAddr(0x1005f41), nextMatch.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertEquals(getAddr(0x1005f3e), nextMatch.getAddress());
    }

    @Test
    public void testLabelMatcherIterator() throws Exception {
        addLabel(0x10018b5, "aLABel");
        Pattern pattern = UserSearchUtils.createSearchPattern("LAB", true);
        ProgramLocation startLocation = new ProgramLocation(program, getAddr(0x1001000));
        ProgramDatabaseFieldSearcher searcher = new LabelFieldSearcher(program, startLocation, null, true, pattern);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        LabelFieldLocation labelLocation = (LabelFieldLocation) nextMatch;
        assertEquals("LAB_010018b3", labelLocation.getName());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        labelLocation = (LabelFieldLocation) nextMatch;
        assertEquals("aLABel", labelLocation.getName());
    }

    @Test
    public void testLabelMatcherIterator2() throws Exception {
        SymbolTable st = program.getSymbolTable();
        int transactionID = program.startTransaction("Test");
        try {
            st.createLabel(getAddr(0x1001950), "LaLaLABel", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001954), "aLABel", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "zzzLABbbbb", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "aaaaLAB123", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "NotAMatch", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "NotAMatchEither", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "myLABEL", SourceType.USER_DEFINED);
        } finally {
            program.endTransaction(transactionID, true);
        }
        Pattern pattern = UserSearchUtils.createSearchPattern("LAB", true);
        ProgramLocation startLocation = new ProgramLocation(program, getAddr(0x1001950));
        ProgramDatabaseFieldSearcher searcher = new LabelFieldSearcher(program, startLocation, null, true, pattern);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        LabelFieldLocation floc = (LabelFieldLocation) nextMatch;
        assertEquals("LaLaLABel", floc.getName());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertEquals("aLABel", floc.getName());
        assertEquals(getAddr(0x1001954), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertNotNull(floc);
        assertEquals("aaaaLAB123", floc.getName());
        assertEquals(getAddr(0x1001960), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertNotNull(floc);
        assertEquals("myLABEL", floc.getName());
        assertEquals(getAddr(0x1001960), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertEquals("zzzLABbbbb", floc.getName());
        assertEquals(getAddr(0x1001960), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        if (nextMatch != null) {
            floc = (LabelFieldLocation) nextMatch;
            assertTrue(floc.getAddress().compareTo(getAddr(0x1001960)) > 0);
        }
    }

    void addEolComment(long longAddr, String comment) {
        SetCommentCmd cmd = new SetCommentCmd(getAddr(longAddr), CodeUnit.EOL_COMMENT, comment);
        tool.execute(cmd, program);
    }

    void addPreComment(long longAddr, String comment) {
        SetCommentCmd cmd = new SetCommentCmd(getAddr(longAddr), CodeUnit.PRE_COMMENT, comment);
        tool.execute(cmd, program);
    }

    void addPostComment(long longAddr, String comment) {
        SetCommentCmd cmd = new SetCommentCmd(getAddr(longAddr), CodeUnit.POST_COMMENT, comment);
        tool.execute(cmd, program);
    }

    void addLabel(long longAddr, String name) {
        AddLabelCmd cmd = new AddLabelCmd(getAddr(longAddr), name, SourceType.USER_DEFINED);
        tool.execute(cmd, program);
    }

    @Test
    public void testTextSearcher() throws Exception {
        addEolComment(0x1001955L, "EOL: PUSH Hit");
        addLabel(0x1001960L, "LabPUSHHit");
        addPreComment(0x1001960L, "PreComment: PUSH Hit");
        addPostComment(0x1001960L, "Post: PUSH hit");
        SearchOptions options = new SearchOptions("PUSH", true, true, true, true, true, true, true, true, true, true, false, false);
        ProgramLocation startLoc = new ProgramLocation(program, getAddr(0x1001950));
        Searcher ts = new ProgramDatabaseSearcher(tool, program, startLoc, null, options, monitor);
        ProgramLocation loc = ts.search();
        assertNotNull(loc);
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
        CommentFieldLocation cloc = (CommentFieldLocation) loc;
        assertEquals(cloc.getCharOffset(), 5);
        // should be 3 hits at address 0x1001960
        loc = ts.search();
        assertNotNull(loc);
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
        assertEquals(getAddr(0x1001960L), loc.getAddress());
        cloc = (CommentFieldLocation) loc;
        assertEquals(cloc.getCharOffset(), 12);
        loc = ts.search();
        assertNotNull(loc);
        assertTrue("Expected LabelFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof LabelFieldLocation));
        LabelFieldLocation floc = (LabelFieldLocation) loc;
        assertEquals(floc.getCharOffset(), 3);
        assertEquals(getAddr(0x1001960L), floc.getAddress());
        loc = ts.search();
        assertEquals(getAddr(0x1001960), loc.getAddress());
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
    }

    @Test
    public void testTextSearcher2() throws Exception {
        // create data and add a comment for it
        StructureDataType s = new StructureDataType("some-PUSHStruct", 0);
        s.add(new ByteDataType());
        s.add(new WordDataType());
        int txId = program.startTransaction("Search Test");
        try {
            // add data
            program.getListing().createData(getAddr(0x1001955L), s, s.getLength());
        } finally {
            program.endTransaction(txId, true);
        }
        // add a post comment
        addPostComment(0x1001955L, "cause PUSH hit");
        SearchOptions options = new SearchOptions("PUSH", true, true, true, true, true, true, true, true, true, true, false, false);
        ProgramLocation startLoc = new ProgramLocation(program, program.getMinAddress().getNewAddress(0x1001950L));
        Searcher ts = new ProgramDatabaseSearcher(tool, program, startLoc, null, options, monitor);
        ProgramLocation loc = ts.search();
        assertEquals(getAddr(0x1001955L), loc.getAddress());
        assertTrue("Expected MnemonicFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof MnemonicFieldLocation));
        loc = ts.search();
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
        assertEquals(CodeUnit.POST_COMMENT, ((CommentFieldLocation) loc).getCommentType());
    }

    @Test
    public void testTextSearcher3() throws Exception {
        int transactionID = program.startTransaction("test");
        try {
            Function f = program.getFunctionManager().getFunctionAt(getAddr(0));
            f.setRepeatableComment("repeatable comment that has imm to cause a hit");
        } finally {
            program.endTransaction(transactionID, true);
        }
        // Test Search All
        SearchOptions options = new // not case sensitive
        SearchOptions(// not case sensitive
        "imm", // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        false, true, false, false);
        ProgramLocation[] locs = searchAll(tool, program, null, null, options, -1, monitor);
        assertNotNull(locs);
        assertTrue("Expected 9 locations, got " + locs.length, (locs.length == 9));
        options = new SearchOptions("Eax", true, true, true, true, true, true, true, true, true, true, false, false);
        locs = searchAll(tool, program, null, null, options, -1, monitor);
        assertNotNull(locs);
        assertEquals(0, locs.length);
    }

    private Address getAddr(long offset) {
        return space.getAddress(offset);
    }

    /**
     * Find all matches according to search options, starting at the address
     * in the startLoc.
     * @param options search options that specify the string to match and where
     * to look for matches.
     * @param startLoc location of where to begin search.
     * @param searchLimit max number of hits to return
     * @return ProgramLocation[] locations that contain matches.
     */
    private ProgramLocation[] searchAll(PluginTool pluginTool, Program searchProgram, ProgramLocation startLoc, AddressSet set, SearchOptions options, int searchLimit, TaskMonitor taskMonitor) {
        int count = 0;
        ArrayList<ProgramLocation> list = new ArrayList<>();
        Searcher ts = new ProgramDatabaseSearcher(pluginTool, searchProgram, startLoc, set, options, taskMonitor);
        ProgramLocation loc = null;
        while ((loc = ts.search()) != null) {
            list.add(loc);
            ++count;
            if (searchLimit > 0 && count >= searchLimit) {
                break;
            }
        }
        ProgramLocation[] locations = new ProgramLocation[list.size()];
        return list.toArray(locations);
    }
}


while ((loc = ts.search()) != null) {
            list.add(loc);
            ++count;
            if (searchLimit > 0 && count >= searchLimit) {
                break;
            }
        }

package ghidra.app.plugin.core.searchtext.quicksearch;

import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.regex.Pattern;
import org.junit.*;
import ghidra.app.cmd.comments.SetCommentCmd;
import ghidra.app.cmd.label.AddLabelCmd;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin;
import ghidra.app.plugin.core.navigation.NextPrevAddressPlugin;
import ghidra.app.plugin.core.searchtext.SearchOptions;
import ghidra.app.plugin.core.searchtext.Searcher;
import ghidra.app.plugin.core.searchtext.databasesearcher.*;
import ghidra.app.services.ProgramManager;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.listing.CodeUnitFormatOptions.ShowBlockName;
import ghidra.program.model.listing.CodeUnitFormatOptions.ShowNamespace;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.symbol.*;
import ghidra.program.util.*;
import ghidra.test.*;
import ghidra.util.UserSearchUtils;
import ghidra.util.task.TaskMonitor;
import junit.framework.TestCase;

public class ProgramDatabaseSearchIteratorTest extends AbstractGhidraHeadedIntegrationTest {

    private Program program;

    private AddressSpace space;

    private TestEnv env;

    private PluginTool tool;

    private Address currentAddress;

    private ToyProgramBuilder builder;

    private TaskMonitor monitor = TaskMonitor.DUMMY;

    public ProgramDatabaseSearchIteratorTest() {
        super();
    }

    private void createIMM(long address) throws MemoryAccessException {
        builder.addBytesMoveImmediate(address, (short) 5);
        builder.disassemble(Long.toHexString(address), 2);
    }

    private void createFallThru(long address) throws MemoryAccessException {
        builder.addBytesFallthrough(address);
        builder.disassemble(Long.toHexString(address), 2);
    }

    @Before
    public void setUp() throws Exception {
        env = new TestEnv();
        tool = env.getTool();
        tool.addPlugin(CodeBrowserPlugin.class.getName());
        tool.addPlugin(NextPrevAddressPlugin.class.getName());
        tool.addPlugin(GoToAddressLabelPlugin.class.getName());
        builder = new ToyProgramBuilder("Test", false);
        program = builder.getProgram();
        builder.createMemory(".text", "0x1001000", 0x1000);
        builder.createMemory(".text", "0x1005000", 0x1000);
        builder.createMemory(".dummy", "0", 100);
        createFallThru(0x1001010);
        createIMM(0x1001100);
        createFallThru(0x1001150);
        createIMM(0x1001200);
        createFallThru(0x1005f00);
        createIMM(0x1005f3e);
        createFallThru(0x1005f50);
        createIMM(0x1005f41);
        createFallThru(0x1005ff0);
        // LAB_010018b3
        createIMM(0x10018b3);
        builder.createMemoryReference("0x1005f41", "0x10018b3", RefType.COMPUTED_JUMP, SourceType.ANALYSIS);
        Parameter p1 = new ParameterImpl(null, new DWordDataType(), program);
        Parameter p2 = new ParameterImpl(null, new DWordDataType(), program);
        p2.setComment("cause a hit! -- imm xxx");
        Parameter p3 = new ParameterImpl(null, new DoubleDataType(), program);
        builder.createEmptyFunction("MyFunc", "0", 26, new WordDataType(), p1, p2, p3);
        builder.createComment("0", "Blah Blah Blah -- imm", CodeUnit.PLATE_COMMENT);
        ProgramManager pm = tool.getService(ProgramManager.class);
        pm.openProgram(program.getDomainFile());
        space = program.getMinAddress().getAddressSpace();
        env.showTool();
    }

    /**
     * @see TestCase#tearDown()
     */
    @After
    public void tearDown() throws Exception {
        env.dispose();
        program = null;
        space = null;
    }

    private ProgramLocation getNextMatch(ProgramDatabaseFieldSearcher searcher) {
        while (currentAddress != null) {
            if (searcher.hasMatch(currentAddress)) {
                return searcher.getMatch();
            }
            currentAddress = searcher.getNextSignificantAddress(currentAddress);
        }
        return null;
    }

    @Test
    public void testEOLCommentIterator() {
        Pattern pattern = UserSearchUtils.createSearchPattern("XXZ*", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CommentFieldSearcher searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        assertNull(getNextMatch(searcher));
        // add a comment with no match
        addEolComment(0x1005146L, "Test EOL comments...");
        searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        assertNull(getNextMatch(searcher));
        // add a comment that has one match
        addEolComment(0x1005d4bL, "Test something with eXXZabc");
        searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation loc = getNextMatch(searcher);
        assertNotNull(loc);
        assertEquals(getAddr(0x1005d4bL), loc.getAddress());
        // add a comment with two matches for a total of 3 matches
        addEolComment(0x100595f, "Hit found: eXXZabc followed by XXZabc");
        searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        loc = getNextMatch(searcher);
        assertNotNull(loc);
        assertEquals(getAddr(0x100595f), loc.getAddress());
        loc = getNextMatch(searcher);
        System.out.println(loc);
        assertEquals(getAddr(0x100595f), loc.getAddress());
        loc = getNextMatch(searcher);
        assertNotNull(loc);
        loc = getNextMatch(searcher);
        assertNull(loc);
    }

    @Test
    public void testSingleWildcard() {
        addEolComment(0x100101cL, "Test EOL comments...");
        addEolComment(0x100101dL, "Test something with eXXZabc");
        addEolComment(0x100101fL, "Hit found: eXXZabc followed by XXZabc");
        Pattern pattern = UserSearchUtils.createSearchPattern("*", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CommentFieldSearcher searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        int count = 0;
        Address[] addrs = new Address[] { getAddr(0x100101cL), getAddr(0x100101dL), getAddr(0x100101fL) };
        ProgramLocation loc = null;
        while ((loc = getNextMatch(searcher)) != null) {
            assertEquals(addrs[count], loc.getAddress());
            ++count;
        }
    }

    @Test
    public void testWildcardInMiddle() {
        addEolComment(0x100101cL, "Test EOL comments...");
        addEolComment(0x100101dL, "Test something with ABCeXXZ123");
        addEolComment(0x100101fL, "Hit found: ABCxyzvvXXZ123 followed by ABCxqa123");
        Pattern pattern = UserSearchUtils.createSearchPattern("ABC*123", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CommentFieldSearcher searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation loc = getNextMatch(searcher);
        assertNotNull(loc);
        assertEquals(getAddr(0x100101dL), loc.getAddress());
        loc = getNextMatch(searcher);
        assertEquals(getAddr(0x100101fL), loc.getAddress());
        loc = getNextMatch(searcher);
        assertEquals(getAddr(0x100101fL), loc.getAddress());
        assertNull(getNextMatch(searcher));
    }

    @Test
    public void testMnemonicOperandIteratorNoMatch() {
        Pattern pattern = UserSearchUtils.createSearchPattern("immxx", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CodeUnitFormat format = new CodeUnitFormat(ShowBlockName.NEVER, ShowNamespace.NEVER);
        ProgramDatabaseFieldSearcher searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, true, pattern, format);
        currentAddress = searcher.getNextSignificantAddress(null);
        assertNull(getNextMatch(searcher));
    }

    @Test
    public void testMnemonicOperandIterator() {
        Pattern pattern = UserSearchUtils.createSearchPattern("imm", true);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        ProgramDatabaseFieldSearcher searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, true, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        startLocation = new ProgramLocation(program, getAddr(0x1001000));
        searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, true, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue("Expected MnemonicFieldLocation, got " + nextMatch.getClass() + " instead!", (nextMatch instanceof MnemonicFieldLocation));
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue("Expected MnemonicFieldLocation, got " + nextMatch.getClass() + " instead!", (nextMatch instanceof MnemonicFieldLocation));
        // now start iterating backwards
        pattern = UserSearchUtils.createSearchPattern("imm", false);
        startLocation = new ProgramLocation(program, getAddr(0x1005f53));
        searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, false, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertEquals(getAddr(0x1005f41), nextMatch.getAddress());
        startLocation = new MnemonicFieldLocation(program, program.getMinAddress().getNewAddress(0x1005f53), null, null, "imm", 2);
        searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, false, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertEquals(getAddr(0x1005f41), nextMatch.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertEquals(getAddr(0x1005f3e), nextMatch.getAddress());
    }

    @Test
    public void testLabelMatcherIterator() throws Exception {
        addLabel(0x10018b5, "aLABel");
        Pattern pattern = UserSearchUtils.createSearchPattern("LAB", true);
        ProgramLocation startLocation = new ProgramLocation(program, getAddr(0x1001000));
        ProgramDatabaseFieldSearcher searcher = new LabelFieldSearcher(program, startLocation, null, true, pattern);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        LabelFieldLocation labelLocation = (LabelFieldLocation) nextMatch;
        assertEquals("LAB_010018b3", labelLocation.getName());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        labelLocation = (LabelFieldLocation) nextMatch;
        assertEquals("aLABel", labelLocation.getName());
    }

    @Test
    public void testLabelMatcherIterator2() throws Exception {
        SymbolTable st = program.getSymbolTable();
        int transactionID = program.startTransaction("Test");
        try {
            st.createLabel(getAddr(0x1001950), "LaLaLABel", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001954), "aLABel", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "zzzLABbbbb", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "aaaaLAB123", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "NotAMatch", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "NotAMatchEither", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "myLABEL", SourceType.USER_DEFINED);
        } finally {
            program.endTransaction(transactionID, true);
        }
        Pattern pattern = UserSearchUtils.createSearchPattern("LAB", true);
        ProgramLocation startLocation = new ProgramLocation(program, getAddr(0x1001950));
        ProgramDatabaseFieldSearcher searcher = new LabelFieldSearcher(program, startLocation, null, true, pattern);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        LabelFieldLocation floc = (LabelFieldLocation) nextMatch;
        assertEquals("LaLaLABel", floc.getName());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertEquals("aLABel", floc.getName());
        assertEquals(getAddr(0x1001954), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertNotNull(floc);
        assertEquals("aaaaLAB123", floc.getName());
        assertEquals(getAddr(0x1001960), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertNotNull(floc);
        assertEquals("myLABEL", floc.getName());
        assertEquals(getAddr(0x1001960), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertEquals("zzzLABbbbb", floc.getName());
        assertEquals(getAddr(0x1001960), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        if (nextMatch != null) {
            floc = (LabelFieldLocation) nextMatch;
            assertTrue(floc.getAddress().compareTo(getAddr(0x1001960)) > 0);
        }
    }

    void addEolComment(long longAddr, String comment) {
        SetCommentCmd cmd = new SetCommentCmd(getAddr(longAddr), CodeUnit.EOL_COMMENT, comment);
        tool.execute(cmd, program);
    }

    void addPreComment(long longAddr, String comment) {
        SetCommentCmd cmd = new SetCommentCmd(getAddr(longAddr), CodeUnit.PRE_COMMENT, comment);
        tool.execute(cmd, program);
    }

    void addPostComment(long longAddr, String comment) {
        SetCommentCmd cmd = new SetCommentCmd(getAddr(longAddr), CodeUnit.POST_COMMENT, comment);
        tool.execute(cmd, program);
    }

    void addLabel(long longAddr, String name) {
        AddLabelCmd cmd = new AddLabelCmd(getAddr(longAddr), name, SourceType.USER_DEFINED);
        tool.execute(cmd, program);
    }

    @Test
    public void testTextSearcher() throws Exception {
        addEolComment(0x1001955L, "EOL: PUSH Hit");
        addLabel(0x1001960L, "LabPUSHHit");
        addPreComment(0x1001960L, "PreComment: PUSH Hit");
        addPostComment(0x1001960L, "Post: PUSH hit");
        SearchOptions options = new SearchOptions("PUSH", true, true, true, true, true, true, true, true, true, true, false, false);
        ProgramLocation startLoc = new ProgramLocation(program, getAddr(0x1001950));
        Searcher ts = new ProgramDatabaseSearcher(tool, program, startLoc, null, options, monitor);
        ProgramLocation loc = ts.search();
        assertNotNull(loc);
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
        CommentFieldLocation cloc = (CommentFieldLocation) loc;
        assertEquals(cloc.getCharOffset(), 5);
        // should be 3 hits at address 0x1001960
        loc = ts.search();
        assertNotNull(loc);
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
        assertEquals(getAddr(0x1001960L), loc.getAddress());
        cloc = (CommentFieldLocation) loc;
        assertEquals(cloc.getCharOffset(), 12);
        loc = ts.search();
        assertNotNull(loc);
        assertTrue("Expected LabelFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof LabelFieldLocation));
        LabelFieldLocation floc = (LabelFieldLocation) loc;
        assertEquals(floc.getCharOffset(), 3);
        assertEquals(getAddr(0x1001960L), floc.getAddress());
        loc = ts.search();
        assertEquals(getAddr(0x1001960), loc.getAddress());
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
    }

    @Test
    public void testTextSearcher2() throws Exception {
        // create data and add a comment for it
        StructureDataType s = new StructureDataType("some-PUSHStruct", 0);
        s.add(new ByteDataType());
        s.add(new WordDataType());
        int txId = program.startTransaction("Search Test");
        try {
            // add data
            program.getListing().createData(getAddr(0x1001955L), s, s.getLength());
        } finally {
            program.endTransaction(txId, true);
        }
        // add a post comment
        addPostComment(0x1001955L, "cause PUSH hit");
        SearchOptions options = new SearchOptions("PUSH", true, true, true, true, true, true, true, true, true, true, false, false);
        ProgramLocation startLoc = new ProgramLocation(program, program.getMinAddress().getNewAddress(0x1001950L));
        Searcher ts = new ProgramDatabaseSearcher(tool, program, startLoc, null, options, monitor);
        ProgramLocation loc = ts.search();
        assertEquals(getAddr(0x1001955L), loc.getAddress());
        assertTrue("Expected MnemonicFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof MnemonicFieldLocation));
        loc = ts.search();
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
        assertEquals(CodeUnit.POST_COMMENT, ((CommentFieldLocation) loc).getCommentType());
    }

    @Test
    public void testTextSearcher3() throws Exception {
        int transactionID = program.startTransaction("test");
        try {
            Function f = program.getFunctionManager().getFunctionAt(getAddr(0));
            f.setRepeatableComment("repeatable comment that has imm to cause a hit");
        } finally {
            program.endTransaction(transactionID, true);
        }
        // Test Search All
        SearchOptions options = new // not case sensitive
        SearchOptions(// not case sensitive
        "imm", // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        false, true, false, false);
        ProgramLocation[] locs = searchAll(tool, program, null, null, options, -1, monitor);
        assertNotNull(locs);
        assertTrue("Expected 9 locations, got " + locs.length, (locs.length == 9));
        options = new SearchOptions("Eax", true, true, true, true, true, true, true, true, true, true, false, false);
        locs = searchAll(tool, program, null, null, options, -1, monitor);
        assertNotNull(locs);
        assertEquals(0, locs.length);
    }

    private Address getAddr(long offset) {
        return space.getAddress(offset);
    }

    /**
     * Find all matches according to search options, starting at the address
     * in the startLoc.
     * @param options search options that specify the string to match and where
     * to look for matches.
     * @param startLoc location of where to begin search.
     * @param searchLimit max number of hits to return
     * @return ProgramLocation[] locations that contain matches.
     */
    private ProgramLocation[] searchAll(PluginTool pluginTool, Program searchProgram, ProgramLocation startLoc, AddressSet set, SearchOptions options, int searchLimit, TaskMonitor taskMonitor) {
        int count = 0;
        ArrayList<ProgramLocation> list = new ArrayList<>();
        Searcher ts = new ProgramDatabaseSearcher(pluginTool, searchProgram, startLoc, set, options, taskMonitor);
        ProgramLocation loc = null;

        ProgramLocation[] locations = new ProgramLocation[list.size()];
        return list.toArray(locations);
    }
}


try {
            // add data
            program.getListing().createData(getAddr(0x1001955L), s, s.getLength());
        } finally {
            program.endTransaction(txId, true);
        }

package ghidra.app.plugin.core.searchtext.quicksearch;

import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.regex.Pattern;
import org.junit.*;
import ghidra.app.cmd.comments.SetCommentCmd;
import ghidra.app.cmd.label.AddLabelCmd;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.navigation.GoToAddressLabelPlugin;
import ghidra.app.plugin.core.navigation.NextPrevAddressPlugin;
import ghidra.app.plugin.core.searchtext.SearchOptions;
import ghidra.app.plugin.core.searchtext.Searcher;
import ghidra.app.plugin.core.searchtext.databasesearcher.*;
import ghidra.app.services.ProgramManager;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.listing.CodeUnitFormatOptions.ShowBlockName;
import ghidra.program.model.listing.CodeUnitFormatOptions.ShowNamespace;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.symbol.*;
import ghidra.program.util.*;
import ghidra.test.*;
import ghidra.util.UserSearchUtils;
import ghidra.util.task.TaskMonitor;
import junit.framework.TestCase;

public class ProgramDatabaseSearchIteratorTest extends AbstractGhidraHeadedIntegrationTest {

    private Program program;

    private AddressSpace space;

    private TestEnv env;

    private PluginTool tool;

    private Address currentAddress;

    private ToyProgramBuilder builder;

    private TaskMonitor monitor = TaskMonitor.DUMMY;

    public ProgramDatabaseSearchIteratorTest() {
        super();
    }

    private void createIMM(long address) throws MemoryAccessException {
        builder.addBytesMoveImmediate(address, (short) 5);
        builder.disassemble(Long.toHexString(address), 2);
    }

    private void createFallThru(long address) throws MemoryAccessException {
        builder.addBytesFallthrough(address);
        builder.disassemble(Long.toHexString(address), 2);
    }

    @Before
    public void setUp() throws Exception {
        env = new TestEnv();
        tool = env.getTool();
        tool.addPlugin(CodeBrowserPlugin.class.getName());
        tool.addPlugin(NextPrevAddressPlugin.class.getName());
        tool.addPlugin(GoToAddressLabelPlugin.class.getName());
        builder = new ToyProgramBuilder("Test", false);
        program = builder.getProgram();
        builder.createMemory(".text", "0x1001000", 0x1000);
        builder.createMemory(".text", "0x1005000", 0x1000);
        builder.createMemory(".dummy", "0", 100);
        createFallThru(0x1001010);
        createIMM(0x1001100);
        createFallThru(0x1001150);
        createIMM(0x1001200);
        createFallThru(0x1005f00);
        createIMM(0x1005f3e);
        createFallThru(0x1005f50);
        createIMM(0x1005f41);
        createFallThru(0x1005ff0);
        // LAB_010018b3
        createIMM(0x10018b3);
        builder.createMemoryReference("0x1005f41", "0x10018b3", RefType.COMPUTED_JUMP, SourceType.ANALYSIS);
        Parameter p1 = new ParameterImpl(null, new DWordDataType(), program);
        Parameter p2 = new ParameterImpl(null, new DWordDataType(), program);
        p2.setComment("cause a hit! -- imm xxx");
        Parameter p3 = new ParameterImpl(null, new DoubleDataType(), program);
        builder.createEmptyFunction("MyFunc", "0", 26, new WordDataType(), p1, p2, p3);
        builder.createComment("0", "Blah Blah Blah -- imm", CodeUnit.PLATE_COMMENT);
        ProgramManager pm = tool.getService(ProgramManager.class);
        pm.openProgram(program.getDomainFile());
        space = program.getMinAddress().getAddressSpace();
        env.showTool();
    }

    /**
     * @see TestCase#tearDown()
     */
    @After
    public void tearDown() throws Exception {
        env.dispose();
        program = null;
        space = null;
    }

    private ProgramLocation getNextMatch(ProgramDatabaseFieldSearcher searcher) {
        while (currentAddress != null) {
            if (searcher.hasMatch(currentAddress)) {
                return searcher.getMatch();
            }
            currentAddress = searcher.getNextSignificantAddress(currentAddress);
        }
        return null;
    }

    @Test
    public void testEOLCommentIterator() {
        Pattern pattern = UserSearchUtils.createSearchPattern("XXZ*", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CommentFieldSearcher searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        assertNull(getNextMatch(searcher));
        // add a comment with no match
        addEolComment(0x1005146L, "Test EOL comments...");
        searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        assertNull(getNextMatch(searcher));
        // add a comment that has one match
        addEolComment(0x1005d4bL, "Test something with eXXZabc");
        searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation loc = getNextMatch(searcher);
        assertNotNull(loc);
        assertEquals(getAddr(0x1005d4bL), loc.getAddress());
        // add a comment with two matches for a total of 3 matches
        addEolComment(0x100595f, "Hit found: eXXZabc followed by XXZabc");
        searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        loc = getNextMatch(searcher);
        assertNotNull(loc);
        assertEquals(getAddr(0x100595f), loc.getAddress());
        loc = getNextMatch(searcher);
        System.out.println(loc);
        assertEquals(getAddr(0x100595f), loc.getAddress());
        loc = getNextMatch(searcher);
        assertNotNull(loc);
        loc = getNextMatch(searcher);
        assertNull(loc);
    }

    @Test
    public void testSingleWildcard() {
        addEolComment(0x100101cL, "Test EOL comments...");
        addEolComment(0x100101dL, "Test something with eXXZabc");
        addEolComment(0x100101fL, "Hit found: eXXZabc followed by XXZabc");
        Pattern pattern = UserSearchUtils.createSearchPattern("*", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CommentFieldSearcher searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        int count = 0;
        Address[] addrs = new Address[] { getAddr(0x100101cL), getAddr(0x100101dL), getAddr(0x100101fL) };
        ProgramLocation loc = null;
        while ((loc = getNextMatch(searcher)) != null) {
            assertEquals(addrs[count], loc.getAddress());
            ++count;
        }
    }

    @Test
    public void testWildcardInMiddle() {
        addEolComment(0x100101cL, "Test EOL comments...");
        addEolComment(0x100101dL, "Test something with ABCeXXZ123");
        addEolComment(0x100101fL, "Hit found: ABCxyzvvXXZ123 followed by ABCxqa123");
        Pattern pattern = UserSearchUtils.createSearchPattern("ABC*123", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CommentFieldSearcher searcher = new CommentFieldSearcher(program, startLocation, null, true, pattern, CodeUnit.EOL_COMMENT);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation loc = getNextMatch(searcher);
        assertNotNull(loc);
        assertEquals(getAddr(0x100101dL), loc.getAddress());
        loc = getNextMatch(searcher);
        assertEquals(getAddr(0x100101fL), loc.getAddress());
        loc = getNextMatch(searcher);
        assertEquals(getAddr(0x100101fL), loc.getAddress());
        assertNull(getNextMatch(searcher));
    }

    @Test
    public void testMnemonicOperandIteratorNoMatch() {
        Pattern pattern = UserSearchUtils.createSearchPattern("immxx", false);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        CodeUnitFormat format = new CodeUnitFormat(ShowBlockName.NEVER, ShowNamespace.NEVER);
        ProgramDatabaseFieldSearcher searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, true, pattern, format);
        currentAddress = searcher.getNextSignificantAddress(null);
        assertNull(getNextMatch(searcher));
    }

    @Test
    public void testMnemonicOperandIterator() {
        Pattern pattern = UserSearchUtils.createSearchPattern("imm", true);
        ProgramLocation startLocation = new ProgramLocation(program, program.getMinAddress());
        ProgramDatabaseFieldSearcher searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, true, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        startLocation = new ProgramLocation(program, getAddr(0x1001000));
        searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, true, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue("Expected MnemonicFieldLocation, got " + nextMatch.getClass() + " instead!", (nextMatch instanceof MnemonicFieldLocation));
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue("Expected MnemonicFieldLocation, got " + nextMatch.getClass() + " instead!", (nextMatch instanceof MnemonicFieldLocation));
        // now start iterating backwards
        pattern = UserSearchUtils.createSearchPattern("imm", false);
        startLocation = new ProgramLocation(program, getAddr(0x1005f53));
        searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, false, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertEquals(getAddr(0x1005f41), nextMatch.getAddress());
        startLocation = new MnemonicFieldLocation(program, program.getMinAddress().getNewAddress(0x1005f53), null, null, "imm", 2);
        searcher = InstructionMnemonicOperandFieldSearcher.createInstructionMnemonicAndOperandFieldSearcher(program, startLocation, null, false, pattern, CodeUnitFormat.DEFAULT);
        currentAddress = searcher.getNextSignificantAddress(null);
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertEquals(getAddr(0x1005f41), nextMatch.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertEquals(getAddr(0x1005f3e), nextMatch.getAddress());
    }

    @Test
    public void testLabelMatcherIterator() throws Exception {
        addLabel(0x10018b5, "aLABel");
        Pattern pattern = UserSearchUtils.createSearchPattern("LAB", true);
        ProgramLocation startLocation = new ProgramLocation(program, getAddr(0x1001000));
        ProgramDatabaseFieldSearcher searcher = new LabelFieldSearcher(program, startLocation, null, true, pattern);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        LabelFieldLocation labelLocation = (LabelFieldLocation) nextMatch;
        assertEquals("LAB_010018b3", labelLocation.getName());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        labelLocation = (LabelFieldLocation) nextMatch;
        assertEquals("aLABel", labelLocation.getName());
    }

    @Test
    public void testLabelMatcherIterator2() throws Exception {
        SymbolTable st = program.getSymbolTable();
        int transactionID = program.startTransaction("Test");
        try {
            st.createLabel(getAddr(0x1001950), "LaLaLABel", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001954), "aLABel", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "zzzLABbbbb", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "aaaaLAB123", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "NotAMatch", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "NotAMatchEither", SourceType.USER_DEFINED);
            st.createLabel(getAddr(0x1001960), "myLABEL", SourceType.USER_DEFINED);
        } finally {
            program.endTransaction(transactionID, true);
        }
        Pattern pattern = UserSearchUtils.createSearchPattern("LAB", true);
        ProgramLocation startLocation = new ProgramLocation(program, getAddr(0x1001950));
        ProgramDatabaseFieldSearcher searcher = new LabelFieldSearcher(program, startLocation, null, true, pattern);
        currentAddress = searcher.getNextSignificantAddress(null);
        ProgramLocation nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        LabelFieldLocation floc = (LabelFieldLocation) nextMatch;
        assertEquals("LaLaLABel", floc.getName());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertEquals("aLABel", floc.getName());
        assertEquals(getAddr(0x1001954), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertNotNull(floc);
        assertEquals("aaaaLAB123", floc.getName());
        assertEquals(getAddr(0x1001960), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertNotNull(floc);
        assertEquals("myLABEL", floc.getName());
        assertEquals(getAddr(0x1001960), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        assertNotNull(nextMatch);
        assertTrue(nextMatch instanceof LabelFieldLocation);
        floc = (LabelFieldLocation) nextMatch;
        assertEquals("zzzLABbbbb", floc.getName());
        assertEquals(getAddr(0x1001960), floc.getAddress());
        nextMatch = getNextMatch(searcher);
        if (nextMatch != null) {
            floc = (LabelFieldLocation) nextMatch;
            assertTrue(floc.getAddress().compareTo(getAddr(0x1001960)) > 0);
        }
    }

    void addEolComment(long longAddr, String comment) {
        SetCommentCmd cmd = new SetCommentCmd(getAddr(longAddr), CodeUnit.EOL_COMMENT, comment);
        tool.execute(cmd, program);
    }

    void addPreComment(long longAddr, String comment) {
        SetCommentCmd cmd = new SetCommentCmd(getAddr(longAddr), CodeUnit.PRE_COMMENT, comment);
        tool.execute(cmd, program);
    }

    void addPostComment(long longAddr, String comment) {
        SetCommentCmd cmd = new SetCommentCmd(getAddr(longAddr), CodeUnit.POST_COMMENT, comment);
        tool.execute(cmd, program);
    }

    void addLabel(long longAddr, String name) {
        AddLabelCmd cmd = new AddLabelCmd(getAddr(longAddr), name, SourceType.USER_DEFINED);
        tool.execute(cmd, program);
    }

    @Test
    public void testTextSearcher() throws Exception {
        addEolComment(0x1001955L, "EOL: PUSH Hit");
        addLabel(0x1001960L, "LabPUSHHit");
        addPreComment(0x1001960L, "PreComment: PUSH Hit");
        addPostComment(0x1001960L, "Post: PUSH hit");
        SearchOptions options = new SearchOptions("PUSH", true, true, true, true, true, true, true, true, true, true, false, false);
        ProgramLocation startLoc = new ProgramLocation(program, getAddr(0x1001950));
        Searcher ts = new ProgramDatabaseSearcher(tool, program, startLoc, null, options, monitor);
        ProgramLocation loc = ts.search();
        assertNotNull(loc);
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
        CommentFieldLocation cloc = (CommentFieldLocation) loc;
        assertEquals(cloc.getCharOffset(), 5);
        // should be 3 hits at address 0x1001960
        loc = ts.search();
        assertNotNull(loc);
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
        assertEquals(getAddr(0x1001960L), loc.getAddress());
        cloc = (CommentFieldLocation) loc;
        assertEquals(cloc.getCharOffset(), 12);
        loc = ts.search();
        assertNotNull(loc);
        assertTrue("Expected LabelFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof LabelFieldLocation));
        LabelFieldLocation floc = (LabelFieldLocation) loc;
        assertEquals(floc.getCharOffset(), 3);
        assertEquals(getAddr(0x1001960L), floc.getAddress());
        loc = ts.search();
        assertEquals(getAddr(0x1001960), loc.getAddress());
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
    }

    @Test
    public void testTextSearcher2() throws Exception {
        // create data and add a comment for it
        StructureDataType s = new StructureDataType("some-PUSHStruct", 0);
        s.add(new ByteDataType());
        s.add(new WordDataType());
        int txId = program.startTransaction("Search Test");

        // add a post comment
        addPostComment(0x1001955L, "cause PUSH hit");
        SearchOptions options = new SearchOptions("PUSH", true, true, true, true, true, true, true, true, true, true, false, false);
        ProgramLocation startLoc = new ProgramLocation(program, program.getMinAddress().getNewAddress(0x1001950L));
        Searcher ts = new ProgramDatabaseSearcher(tool, program, startLoc, null, options, monitor);
        ProgramLocation loc = ts.search();
        assertEquals(getAddr(0x1001955L), loc.getAddress());
        assertTrue("Expected MnemonicFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof MnemonicFieldLocation));
        loc = ts.search();
        assertTrue("Expected CommentFieldLocation, got " + loc.getClass() + " instead!", (loc instanceof CommentFieldLocation));
        assertEquals(CodeUnit.POST_COMMENT, ((CommentFieldLocation) loc).getCommentType());
    }

    @Test
    public void testTextSearcher3() throws Exception {
        int transactionID = program.startTransaction("test");
        try {
            Function f = program.getFunctionManager().getFunctionAt(getAddr(0));
            f.setRepeatableComment("repeatable comment that has imm to cause a hit");
        } finally {
            program.endTransaction(transactionID, true);
        }
        // Test Search All
        SearchOptions options = new // not case sensitive
        SearchOptions(// not case sensitive
        "imm", // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        true, // not case sensitive
        false, true, false, false);
        ProgramLocation[] locs = searchAll(tool, program, null, null, options, -1, monitor);
        assertNotNull(locs);
        assertTrue("Expected 9 locations, got " + locs.length, (locs.length == 9));
        options = new SearchOptions("Eax", true, true, true, true, true, true, true, true, true, true, false, false);
        locs = searchAll(tool, program, null, null, options, -1, monitor);
        assertNotNull(locs);
        assertEquals(0, locs.length);
    }

    private Address getAddr(long offset) {
        return space.getAddress(offset);
    }

    /**
     * Find all matches according to search options, starting at the address
     * in the startLoc.
     * @param options search options that specify the string to match and where
     * to look for matches.
     * @param startLoc location of where to begin search.
     * @param searchLimit max number of hits to return
     * @return ProgramLocation[] locations that contain matches.
     */
    private ProgramLocation[] searchAll(PluginTool pluginTool, Program searchProgram, ProgramLocation startLoc, AddressSet set, SearchOptions options, int searchLimit, TaskMonitor taskMonitor) {
        int count = 0;
        ArrayList<ProgramLocation> list = new ArrayList<>();
        Searcher ts = new ProgramDatabaseSearcher(pluginTool, searchProgram, startLoc, set, options, taskMonitor);
        ProgramLocation loc = null;
        while ((loc = ts.search()) != null) {
            list.add(loc);
            ++count;
            if (searchLimit > 0 && count >= searchLimit) {
                break;
            }
        }
        ProgramLocation[] locations = new ProgramLocation[list.size()];
        return list.toArray(locations);
    }
}