package the8472.bencode; import java.nio.ByteBuffer; import java.util.Arrays; import the8472.bencode.Tokenizer.DictState; import the8472.bencode.Tokenizer.Token; import the8472.bencode.Tokenizer.TokenConsumer; import the8472.bencode.Tokenizer.TokenType; public class PathMatcher implements TokenConsumer { // want a -> v -> following key // push dict, push string, pop string, push map, push string, pop string, push any, pop any final ByteBuffer[] elements; ByteBuffer result; Tokenizer t; int matchDepth = 1; public PathMatcher(String... path) { elements = Arrays.stream(path).map(Utils::str2buf).toArray(ByteBuffer[]::new); } public void tokenizer(Tokenizer t) { this.t = t; t.consumer = this; } @Override public void pop(Token st) { int depth = t.stackIdx(); //System.out.println("pop"+st+" d"+depth+" m"+matchDepth); if(depth == matchDepth && matchDepth - 1 == elements.length) { Token dict = t.atStackOffset(-1); if(dict.expect() == DictState.ExpectValue) { //System.out.println("result"); result = t.getSlice(st); matchDepth = Integer.MAX_VALUE; } } if(st.type() == TokenType.STRING && matchDepth - 1 < elements.length) { int dictDepth = depth - 2; if(dictDepth == matchDepth) { Token dict = t.atStackOffset(-2); if(dict == null) return; if(dict.expect() == DictState.ExpectKeyOrEnd) { ByteBuffer val = t.getSlice(st); if(val.equals(elements[matchDepth - 1])) { //System.out.println("match"); matchDepth++; } } } } } @Override public void push(Token st) { //System.out.println("push"+st+" d"+t.stackIdx()); } public ByteBuffer match(ByteBuffer buf) { t.inputBuffer(buf); t.tokenize(); return result; } }