162 lines
5.0 KiB
Java
162 lines
5.0 KiB
Java
/*
|
|
Copyright 2018-2022 Dmitry Isaenko
|
|
|
|
This file is part of NS-USBloader.
|
|
|
|
NS-USBloader is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
NS-USBloader is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
package nsusbloader.Utilities.patches.es;
|
|
|
|
import libKonogonka.Converter;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
public class SimplyFind {
|
|
private String what;
|
|
private final byte[] where;
|
|
|
|
private Matcher matcherHex;
|
|
private Matcher matcherDot;
|
|
|
|
private final List<Integer> findings = new ArrayList<>();
|
|
private final int statementLength;
|
|
private final List<SearchBlock> searchBlocks = new ArrayList<>();
|
|
/**
|
|
* Abstraction layer for searching patterns like "..CAFE..BE" in bytes array.
|
|
* It's 'String' combination of hex values and '.' which stands for unknown value.
|
|
* Returns offset of the first symbol.
|
|
* */
|
|
public SimplyFind(String what, byte[] where){
|
|
this.where = where;
|
|
if (! what.contains(".")){
|
|
doKMPSearch(Converter.hexStringToByteArray(what), 0);
|
|
this.statementLength = what.length()/2;
|
|
return;
|
|
}
|
|
this.what = what.replaceAll("\\.", "\\.\\.");
|
|
this.statementLength = this.what.length()/2;
|
|
|
|
buildSearchingSequence();
|
|
complexSearch();
|
|
}
|
|
private void buildSearchingSequence(){
|
|
Pattern patternHex = Pattern.compile("[0-9]|[A-F]|[a-f]");
|
|
Pattern patternDot = Pattern.compile("\\.");
|
|
this.matcherHex = patternHex.matcher(what);
|
|
this.matcherDot = patternDot.matcher(what);
|
|
|
|
int nextDotPos = 0;
|
|
int nextHexPos;
|
|
|
|
while(true){
|
|
nextHexPos = getNextNumberPosition(nextDotPos);
|
|
if (nextHexPos == -1)
|
|
break;
|
|
|
|
nextDotPos = getNextDotPosition(nextHexPos);
|
|
if (nextDotPos == -1) {
|
|
searchBlocks.add(new SearchBlock(what.substring(nextHexPos), nextHexPos));
|
|
break;
|
|
}
|
|
String searchStatement = what.substring(nextHexPos, nextDotPos);
|
|
searchBlocks.add(new SearchBlock(searchStatement, nextHexPos));
|
|
}
|
|
}
|
|
private int getNextNumberPosition(int since){
|
|
if (matcherHex.find(since))
|
|
return matcherHex.start();
|
|
return -1;
|
|
}
|
|
|
|
private int getNextDotPosition(int since){
|
|
if (matcherDot.find(since))
|
|
return matcherDot.start();
|
|
return -1;
|
|
}
|
|
|
|
private void complexSearch(){
|
|
SearchBlock block = searchBlocks.get(0);
|
|
doKMPSearch(block.statement, block.offsetInStatement);
|
|
findings.removeIf(this::searchForward);
|
|
}
|
|
private boolean searchForward(int offset){
|
|
for (int i = 1; i < searchBlocks.size(); i++) {
|
|
SearchBlock block = searchBlocks.get(i);
|
|
if (! doDumbSearch(block.statement, offset+block.offsetInStatement)){
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void doKMPSearch(byte[] subject, int skip){
|
|
int whereSize = where.length;
|
|
int subjectSize = subject.length;
|
|
|
|
int[] pf = new int[subjectSize];
|
|
|
|
int j = 0;
|
|
for (int i = 1; i < subjectSize; i++ ) {
|
|
while ((j > 0) && (subject[j] != subject[i]))
|
|
j = pf[j-1];
|
|
if (subject[j] == subject[i])
|
|
j++;
|
|
pf[i] = j;
|
|
}
|
|
|
|
j = 0;
|
|
for (int i = 0; i < whereSize; i++){
|
|
while ((j > 0) && (subject[j] != where[i]))
|
|
j = pf[j - 1];
|
|
if (subject[j] == where[i])
|
|
j++;
|
|
if (j == subjectSize) {
|
|
findings.add(i-j+1-skip);
|
|
j = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean doDumbSearch(byte[] subject, int since){
|
|
for (int i = 0; i < subject.length; i++) {
|
|
if (where[since + i] != subject[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public int getStatementLength() {
|
|
return statementLength;
|
|
}
|
|
|
|
public List<Integer> getResults(){
|
|
return findings;
|
|
}
|
|
|
|
private static class SearchBlock{
|
|
byte[] statement;
|
|
int offsetInStatement;
|
|
|
|
SearchBlock(String statement, int offset){
|
|
if (statement != null) {
|
|
this.statement = Converter.hexStringToByteArray(statement);
|
|
}
|
|
this.offsetInStatement = offset/2;
|
|
}
|
|
}
|
|
}
|