From 9317e6626c6e4bb94fedacaf2b2c4c46f452b9bc Mon Sep 17 00:00:00 2001 From: serega6531 Date: Mon, 9 Mar 2020 23:00:40 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BD=D1=8B=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D1=81=D0=B5=D0=BA=D0=B0=D1=8E=D1=89=D0=B8?= =?UTF-8?q?=D0=B5=D1=81=D1=8F=20=D0=BC=D0=B0=D1=82=D1=87=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../packmate/service/PatternMatcher.java | 107 ++++++++++++++++++ .../packmate/service/PatternService.java | 81 +------------ 2 files changed, 110 insertions(+), 78 deletions(-) create mode 100644 src/main/java/ru/serega6531/packmate/service/PatternMatcher.java diff --git a/src/main/java/ru/serega6531/packmate/service/PatternMatcher.java b/src/main/java/ru/serega6531/packmate/service/PatternMatcher.java new file mode 100644 index 0000000..2b19aef --- /dev/null +++ b/src/main/java/ru/serega6531/packmate/service/PatternMatcher.java @@ -0,0 +1,107 @@ +package ru.serega6531.packmate.service; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.crypto.codec.Hex; +import ru.serega6531.packmate.model.FoundPattern; +import ru.serega6531.packmate.model.Pattern; +import ru.serega6531.packmate.model.enums.PatternSearchType; +import ru.serega6531.packmate.utils.Bytes; + +import java.util.*; +import java.util.regex.Matcher; + +public class PatternMatcher { + + private static final Map compiledPatterns = new HashMap<>(); + + private final byte[] contentBytes; + private final String content; + private final List patterns; + + private final Set result = new HashSet<>(); + + public PatternMatcher(byte[] contentBytes, List patterns) { + this.contentBytes = contentBytes; + this.content = new String(contentBytes); + this.patterns = patterns; + } + + public Set findMatches() { + patterns.forEach(this::match); + return result; + } + + private void match(Pattern pattern) { + if (pattern.getSearchType() == PatternSearchType.REGEX) { + final java.util.regex.Pattern regex = compilePattern(pattern); + final Matcher matcher = regex.matcher(content); + int startPos = 0; + + while (matcher.find(startPos)) { + addIfPossible(FoundPattern.builder() + .patternId(pattern.getId()) + .startPosition(matcher.start()) + .endPosition(matcher.end() - 1) + .build()); + startPos = matcher.end(); + } + } else if (pattern.getSearchType() == PatternSearchType.SUBSTRING) { + int startSearch = 0; + final String value = pattern.getValue(); + + while (true) { + int start = StringUtils.indexOfIgnoreCase(content, value, startSearch); + + if (start == -1) { + return; + } + + int end = start + value.length() - 1; + addIfPossible(FoundPattern.builder() + .patternId(pattern.getId()) + .startPosition(start) + .endPosition(end) + .build()); + + startSearch = end + 1; + } + } else { // SUBBYTES + int startSearch = 0; + final byte[] value = Hex.decode(pattern.getValue()); + + while (true) { + int start = Bytes.indexOf(contentBytes, value, startSearch, contentBytes.length); + + if (start == -1) { + return; + } + + int end = start + value.length - 1; + addIfPossible(FoundPattern.builder() + .patternId(pattern.getId()) + .startPosition(start) + .endPosition(end) + .build()); + + startSearch = end + 1; + } + } + } + + private void addIfPossible(FoundPattern found) { + if (result.stream().noneMatch(match -> between(match.getStartPosition(), match.getEndPosition(), found.getStartPosition()) || + between(match.getStartPosition(), match.getEndPosition(), found.getEndPosition()))) { + result.add(found); + } + } + + private boolean between(int a, int b, int x) { + return a <= x && x <= b; + } + + + private java.util.regex.Pattern compilePattern(Pattern pattern) { + return compiledPatterns.computeIfAbsent(pattern.getValue(), java.util.regex.Pattern::compile); + } + +} diff --git a/src/main/java/ru/serega6531/packmate/service/PatternService.java b/src/main/java/ru/serega6531/packmate/service/PatternService.java index efbb186..2cc982d 100644 --- a/src/main/java/ru/serega6531/packmate/service/PatternService.java +++ b/src/main/java/ru/serega6531/packmate/service/PatternService.java @@ -1,24 +1,19 @@ package ru.serega6531.packmate.service; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; -import org.springframework.security.crypto.codec.Hex; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.serega6531.packmate.model.FoundPattern; import ru.serega6531.packmate.model.Pattern; import ru.serega6531.packmate.model.Stream; import ru.serega6531.packmate.model.enums.PatternDirectionType; -import ru.serega6531.packmate.model.enums.PatternSearchType; import ru.serega6531.packmate.model.enums.SubscriptionMessageType; import ru.serega6531.packmate.model.pojo.SubscriptionMessage; import ru.serega6531.packmate.repository.PatternRepository; -import ru.serega6531.packmate.utils.Bytes; import java.util.*; -import java.util.regex.Matcher; import java.util.stream.Collectors; @Service @@ -30,7 +25,6 @@ public class PatternService { private final StreamSubscriptionService subscriptionService; private final Map patterns = new HashMap<>(); - private final Map compiledPatterns = new HashMap<>(); @Autowired public PatternService(PatternRepository repository, @@ -53,75 +47,11 @@ public class PatternService { } public Set findMatches(byte[] bytes, boolean incoming) { - return patterns.values().stream() + final List list = patterns.values().stream() .filter(p -> p.getDirectionType() == (incoming ? PatternDirectionType.INPUT : PatternDirectionType.OUTPUT) || p.getDirectionType() == PatternDirectionType.BOTH) - .map(pattern -> match(pattern, bytes)) - .flatMap(List::stream) - .collect(Collectors.toSet()); - } - - private List match(Pattern pattern, byte[] bytes) { - List found = new ArrayList<>(); - - if (pattern.getSearchType() == PatternSearchType.REGEX) { - String content = new String(bytes); - final java.util.regex.Pattern regex = compilePattern(pattern); - final Matcher matcher = regex.matcher(content); - int startPos = 0; - - while (matcher.find(startPos)) { - found.add(FoundPattern.builder() - .patternId(pattern.getId()) - .startPosition(matcher.start()) - .endPosition(matcher.end() - 1) - .build()); - startPos = matcher.end(); - } - - return found; - } else if (pattern.getSearchType() == PatternSearchType.SUBSTRING) { - String content = new String(bytes); - int startSearch = 0; - final String value = pattern.getValue(); - - while (true) { - int start = StringUtils.indexOfIgnoreCase(content, value, startSearch); - - if (start == -1) { - return found; - } - - int end = start + value.length() - 1; - found.add(FoundPattern.builder() - .patternId(pattern.getId()) - .startPosition(start) - .endPosition(end) - .build()); - - startSearch = end + 1; - } - } else { // SUBBYTES - int startSearch = 0; - final byte[] value = Hex.decode(pattern.getValue()); - - while (true) { - int start = Bytes.indexOf(bytes, value, startSearch, bytes.length); - - if (start == -1) { - return found; - } - - int end = start + value.length - 1; - found.add(FoundPattern.builder() - .patternId(pattern.getId()) - .startPosition(start) - .endPosition(end) - .build()); - - startSearch = end + 1; - } - } + .collect(Collectors.toList()); + return new PatternMatcher(bytes, list).findMatches(); } @Transactional @@ -138,7 +68,6 @@ public class PatternService { pattern.getMatchedStreams().clear(); patterns.remove(id); - compiledPatterns.remove(pattern.getValue()); repository.delete(pattern); subscriptionService.broadcast(new SubscriptionMessage(SubscriptionMessageType.DELETE_PATTERN, id)); } @@ -152,8 +81,4 @@ public class PatternService { return saved; } - private java.util.regex.Pattern compilePattern(Pattern pattern) { - return compiledPatterns.computeIfAbsent(pattern.getValue(), java.util.regex.Pattern::compile); - } - }