All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fqlite.pattern.SerialTypeMatcher Maven / Gradle / Ivy

package fqlite.pattern;

import java.nio.ByteBuffer;

import fqlite.util.Auxiliary;
import fqlite.util.BufferUtil;

/**
 * An engine that performs match operations on a byte buffer sequence by
 * interpreting a pattern.
 * 
 * @author pawlaszc
 *
 */
public class SerialTypeMatcher {

	HeaderPattern pattern = null;
	ByteBuffer buffer = null;
	int pos = 0;
	int startRegion;
	int endRegion;
	int start;
	int end;
	MatchingMode mode = MatchingMode.NORMAL;

	/**
	 * Constructor.
	 * 
	 * @param buffer ByteBuffer to analyze
	 */
	public SerialTypeMatcher(ByteBuffer buffer) {
		this.buffer = buffer;
		startRegion = 0;
		endRegion = buffer.capacity();
		buffer.position(0);
	}

	/**
	 * Change the matching behavior. You can choose between:
	 * NORMAL,NOHEADER,NO1STCOL.
	 * 
	 * @param newMode the matching mode
	 */
	public void setMatchingMode(MatchingMode newMode) {
		mode = newMode;
	}

	public MatchingMode getMachtingMode() {
		return mode;
	}

	/**
	 * Set a list of matching constrains.
	 * 
	 * @param pattern the pattern
	 */
	public void setPattern(HeaderPattern pattern) {
		this.pattern = pattern;
	}

	/**
	 * Sets the limits of this matcher's region.
	 * 
	 * @param from the start of the region
	 * @param to the end of the region
	 */
	public void region(int from, int to) {
		this.startRegion = from;
		this.endRegion = to;
		// renew position for search
		buffer.position(from);
	}

	/**
	 * Returns the offset after the last character matched.
	 * 
	 * @return The offset after the last character matched
	 */
	public int end() {
		return end;
	}

	/**
	 * Returns the start indices of the previous match.
	 *
	 * @return The indices of the first byte matched
	 */
	public int start() {
		return start;
	}

	/**
	 * This method starts at the beginning of this matcher's region, or, if a
	 * previous invocation of the method was successful and the matcher has not
	 * since been reset, at the first character not matched by the previous match.
	 * If the match succeeds then more information can be obtained via the start,
	 * end, and group methods.
	 *
	 * @return true if, and only if, a subsequence of the input sequence matches
	 *         this matcher's pattern
	 */
	public boolean find() {
		

		int idx = 0;
		switch (mode) {
		case NORMAL:
			idx = 0;
			break;

		case NOHEADER:
			idx = 1;
			break;

		case NO1stCOL:
			idx = 2;
			break;
		}
		int i = idx;

		/* check pattern constrain by constrain */
  
		if (i < pattern.size()) {
    		while (i < pattern.size()) {
    			/* do not read out of bounds - stop before the end */
    			if (buffer.position() < (endRegion - 4)) {
    				/* remember the begin of a possible match */
    				int current = buffer.position();
    				if (i == idx)
    					pos = current;
    				/* read next value */
    				int value = readUnsignedVarInt();
    				// no varint OR costrain does not match -> skip this an go on with the next
    				// bytes
    				if (value == -1 || !pattern.get(i).match(value)) {
    					current++;
    					buffer.position(current);
    					/* and again, startRegion the beginning but with the next byte */
    					i = idx;
    					/* skip pattern matching step and try again */
    					continue;
    				}
    
    				/* go ahead with next constrain */
    				i++;
    
    			} else
    				return false; /* no match could be found */
    
    		}
		} else {
		    // move position forward, as start index is bigger than pattern size
		    pos = buffer.position() + 1;
		    return false;
		}

		start = pos;
		end = buffer.position();
		if (end <= start)
			return false;
		
		return true; // byte number of the match
	}

	/**
	 * Returns the input subsequence matched by the previous match. For a matcher m
	 * with input sequence s, the expressions m.group() and s.substring(m.start(),
	 * m.end()) are equivalent.
	 * 
	 * @return The (possibly empty) subsequence matched by the previous match
	 */
	public ByteBuffer group() {
		byte[] match = BufferUtil.allocateByteBuffer((end) - start);
		buffer.position(start);
		buffer.get(match, 0, (end - start));
		return ByteBuffer.wrap(match);
	}

	/**
	 * Returns the input subsequence matched by the previous match. The return value
	 * contains a hex-representation of the match byte values.
	 * 
	 * @param start the start index of the match
	 * @param end the end index of the match
	 * @return the matched substring
	 */
	public String substring(int start, int end) {
		if (start > end)
			return "";
		byte[] match = BufferUtil.allocateByteBuffer((end) - start);
		buffer.position(start);
		buffer.get(match, 0, (end - start));
		return Auxiliary.bytesToHex(match);
	}

	/**
	 * Returns the input subsequence matched by the previous match. The return value
	 * contains a hex-representation of the match byte values.
	 * 
	 * @return hex representation of matched group
	 */
	public String group2Hex() {
		return substring(start, end);
	}

	/**
	 * Try to read the next varint value from the buffer.
	 * 
	 * @return the corresponding int value or -1 if no varint could be found.
	 */
	public int readUnsignedVarInt() {
		int value = 0;
		int b = 0;
		int counter = 0;
		int shift = 0;

		// as long as we have a byte with most significant bit value 1
		// there are more byte to read
		// we only read a maximum of 3 bytes (8 bytes would be possible to)
		while ((((b = buffer.get()) & 0x80) != 0) && counter < 3) {
			counter++;
			shift += 7;
			value |= (b & 0x7F) << shift;
		}
		// last rightmost byte has always need to have a 0 at the MSB
		// hence, if there is a 1 -> no varint value
		if ((b & 0x80) != 0)
			return -1;

		// return a normalized integer value
		return value | b;
	}

	

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy