private void searchBlock(SequenceSearchState rootState, Program program, MemoryBlock block,
			AddressSetView restrictSet, TaskMonitor monitor)
			throws IOException, CancelledException {

		// if no restricted set, make restrict set the full block
		AddressSet doneSet;
		if (restrictSet == null || restrictSet.isEmpty()) {
			doneSet = new AddressSet(block.getStart(), block.getEnd());
		}
		else {
			doneSet = restrictSet.intersectRange(block.getStart(), block.getEnd());
		}

		long numInDoneSet = doneSet.getNumAddresses();
		long numInBlock = block.getSize();

		Address blockStartAddr = block.getStart();

		// pull each range off the restricted set
		long progress = monitor.getProgress();
		AddressRangeIterator addressRanges = doneSet.getAddressRanges();
		long numDone = 0;
		while (addressRanges.hasNext()) {
			monitor.checkCancelled();
			monitor.setMessage(searchName + " Search");
			monitor.setProgress(progress + (long) (numInBlock * ((float) numDone / numInDoneSet)));
			AddressRange addressRange = addressRanges.next();
			long numAddressesInRange = addressRange.getLength();

			ArrayList<Match> mymatches = new ArrayList<>();

			long streamoffset = blockStartAddr.getOffset();

			// Give block a starting/ending point before this address to search
			//    patterns might start before, since they have a pre-pattern
			// TODO: this is dangerous, since pattern might be very big, but the set should be restricted
			//       normally only when we are searching for more matching patterns that had a postrule that didn't satisfy
			//       normally the whole memory blocks will get searched.
			long blockOffset = addressRange.getMinAddress().subtract(blockStartAddr);
			blockOffset = blockOffset - RESTRICTED_PATTERN_BYTE_RANGE;
			if (blockOffset <= 0) {
				// don't go before the block start
				blockOffset = 0;
			}

			// compute number of bytes in the range + 1, and don't search more than that.
			long maxBlockSearchLength =
				addressRange.getMaxAddress().subtract(blockStartAddr) - blockOffset + 1;

			InputStream data = block.getData();
			data.skip(blockOffset);

			rootState.apply(data, maxBlockSearchLength, mymatches, monitor);
			monitor.checkCancelled();

			monitor.setMessage(searchName + " (Examine Matches)");

			// TODO: DANGER there is much offset<-->address calculation here
			//       should be OK, since they are all relative to the block.
			long matchProgress = progress + (long) (numInBlock * ((float) numDone / numInDoneSet));
			for (int i = 0; i < mymatches.size(); ++i) {
				monitor.checkCancelled();
				monitor.setProgress(
					matchProgress + (long) (numAddressesInRange * ((float) i / mymatches.size())));
				Match match = mymatches.get(i);
				Address addr = blockStartAddr.add(match.getMarkOffset() + blockOffset);
				if (!match.checkPostRules(streamoffset + blockOffset)) {
					continue;
				}

				MatchAction[] matchactions = match.getMatchActions();
				preMatchApply(matchactions, addr);
				for (MatchAction matchaction : matchactions) {
					matchaction.apply(program, addr, match);
				}

				postMatchApply(matchactions, addr);
			}

			numDone += numAddressesInRange;
		}
	}
Search through bytes of a memory block using the finite state machine -root-
Apply any additional rules for matching patterns.

@param program is the Program being searched
@param block is the specific block of bytes being searched

@throws IOException exception during read of memory
@throws CancelledException canceled search
Ghidra/Features/Base/src/main/java/ghidra/util/bytesearch/MemoryBytePatternSearcher.java