/** * Copyright 2007-2015, Kaazing Corporation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kaazing.k3po.driver.internal.buffer; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferIndexFinder; /** * Use the Knuth-Morris-Pratt (KMP) pattern matching algorithm for matching a * byte array (pattern or "word") within a given byte array ("text"): * * http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm * * This is similar to String.contains(), except that we can use it on byte * arrays (e.g. hex strings) as well. * * This particular implementation was found at: * * http://helpdesk.objects.com.au/java/search-a-byte-array-for-a-byte-sequence */ public class FastIndexFinder implements ChannelBufferIndexFinder { private byte[] pattern; private int[] partialMatch; // Generate the "partial match" table (aka the "failure function") private void generatePartialMatch() { partialMatch = new int[pattern.length]; int j = 0; for (int i = 1; i < pattern.length; i++) { while (j > 0 && pattern[j] != pattern[i]) { j = partialMatch[j - 1]; } if (pattern[j] == pattern[i]) { j++; } partialMatch[i] = j; } } public FastIndexFinder(byte[] pattern) { this.pattern = pattern; generatePartialMatch(); } public FastIndexFinder(ChannelBuffer buf) { int len = buf.readableBytes(); pattern = new byte[len]; buf.getBytes(buf.readerIndex(), pattern); generatePartialMatch(); } @Override public boolean find(ChannelBuffer buf, int guessedIndex) { int j = 0; // Due to the structure of the ChannelBufferIndexFinder API (i.e. // a single method which only returns true/false, not the index at // which a match is found), we have to have this simplistic check // first. if (buf.getByte(guessedIndex) != pattern[j]) { return false; } for (int i = guessedIndex; i < buf.readableBytes(); i++) { while (j > 0 && pattern[j] != buf.getByte(i)) { j = partialMatch[j - 1]; // Same problem as previous comment. If we have to go back and // look for the first character in the pattern // then we have to return false. if (j == 0) { return false; } } if (pattern[j] == buf.getByte(i)) { j++; } if (j == pattern.length) { return true; } } return false; } }