<commit_before>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package net.sf.jaer.eventio;

import java.awt.Point;
import java.io.IOException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;

import eu.seebetter.ini.chips.davis.DavisBaseCamera;
import net.sf.jaer.aemonitor.AEPacketRaw;
import net.sf.jaer.aemonitor.EventRaw.EventType;
import net.sf.jaer.chip.AEChip;
import net.sf.jaer.chip.EventExtractor2D;
import net.sf.jaer.chip.RetinaExtractor;
import net.sf.jaer.event.ApsDvsEvent;
import net.sf.jaer.event.ApsDvsEvent.ReadoutType;
import net.sf.jaer.event.ApsDvsEventPacket;
import net.sf.jaer.event.EventPacket;
import net.sf.jaer.event.OutputEventIterator;

/**
 * This class parses the buffer from the data files or network streams
 * containing jAER 3.0 format data, as specified in
 * http://inilabs.com/support/software/fileformat/
 *
 * The most useful public interface for outside is the getJaer2EventBuf(), by
 * this method, the event buffer just include addr and timestamp (like jAER 2.0
 * did) will be returned. After get this buffer similar to jAER 2.0, all other
 * things will be processed by AEFileInputStream. The stream will be treated
 * like it's a jAER 2.0 buffer.
 *
 * @author <NAME>
 * @author tobi
 */
public class Jaer3BufferParser {

    private static final Logger log = Logger.getLogger("net.sf.jaer.eventio");
//	private int BUFFER_CAPACITY_BYTES = 8 * 1000000;
    private ByteBuffer in = null; // no reason to allocate here since it is copied reference from constuctor  (tobi) // ByteBuffer.allocate(BUFFER_CAPACITY_BYTES);
    // private ByteBuffer out = ByteBuffer.allocate(BUFFER_CAPACITY_BYTES);

    private final int PKT_HEADER_SIZE = 28;

    private int framePixelArrayOffset = 0; // Just for frame events and this is the origin index
    private int translatedArrayIndex = 0; // This is the correct index, in fact it's the transpose of the origin array.

    private PacketDescriptor currentPkt = new PacketDescriptor();
    private long numEvents = 0;

    /**
     * These points are the first and last pixel APS read out from the array.
     * Subclasses must set and use these values in the firstFrameAddress and
     * lastFrameAddress methods and event filters that transform the APS
     * addresses can modify these values to properly account for the order of
     * readout, e.g. in RotateFilter.
     *
     */
    protected Point apsFirstPixelReadOut = null, apsLastPixelReadOut = null;
    /**
     * The AEChip object associated with this stream. This field was added for
     * supported jAER 3.0 format files to support translating bit locations in
     * events.
     */
    private AEChip chip = null;

    /**
     * Field for decoding jaer 3.1 dvs address. Note these fields are overridden
     * by AEFileInputStream.parseFileFormatVersion. These codes get the
     * addresses from the AEDAT-3.1 data fields, which are then used to recode
     * them to the AEDAT-2.0 format used internally and by existing AEChip
     * EventExtractors, using the constants specified in
     * eu.seebetter.ini.chips.DavisChip. See
     * http://inilabs.com/support/software/fileformat/
     *
     * @see AEFileInputStream#parseFileFormatVersion(java.lang.String) - sets
     * these constants according to file type
     */
    public static int JAER3YSHIFT = 2, JAER3YMASK = 0x07FFF << JAER3YSHIFT, // ?? 3.0 is 15 bits from bits 22 to 30, 3.1 is 14 bits from bits 18 to 31.
            JAER3XSHIFT = 17, JAER3XMASK = 0x07FFF << JAER3XSHIFT, // ?? 3.0 is 15 bits from bits 12 to 21, 3.1 is 14 bits from bits from 4 to 17.
            JAER3POLSHIFT = 1, JAER3POLMASK = 1 << JAER3POLSHIFT, // , // ?? 1 bit at bit 11
            JAER3VALIDITY_BIT = 0; // marks filtered out events, 0 in the 0th bit of the first byte means invalid, 1 means valid. 
    /**
     * Field for decoding jaer 3.1 aps address
     */
    public static final int JAER3APSYSHIFT = 0, JAER3APSYMASK = 65535 << JAER3APSYSHIFT, // 16 bits from bits 16 to 31
            JAER3APSXSHIFT = 16, JAER3APSXMASK = 65535 << JAER3APSXSHIFT; // 16 bits from bits 0 to 15

    private boolean inFrameEvent = false; // TODO a flag used to represent the current event is in the frame or not.
    // The reason why we use this flag is that a whole frame events is divided into several pixels data, and current in jaer, every
    // pixel data is packed as one single complete jaer 2 event.
    private int frameCurrentEventOffset; // TODO ?? counter for something
    private boolean readOutType = false; // TODO ?? flag for something

    private static AEChip ORIGINAL_CHIP = null;
    private static EventExtractor2D ORIGINAL_EVENT_EXTRACTOR = null;

    private static Jaer3EventExtractor JAER3_EXTRACTOR = null;

    public class PacketHeader {

        EventType eventType = EventType.SpecialEvent;
        int eventSource = 0;
        int eventSize = 0;
        int eventTSOffset = 0;
        int eventTSOverflow = 0;
        int eventCapacity = 0;
        int eventNumber = 0;
        int eventValid = 0;
    }

    public class PacketDescriptor {

        private PacketHeader pktHeader;
        private int pktPosition;

        public PacketDescriptor() {
            pktHeader = new PacketHeader();
            pktPosition = 0;
        }

        public PacketHeader getPktHeader() {
            return pktHeader;
        }

        public int getPktPosition() {
            return pktPosition;
        }

        public void SetPktHeader(PacketHeader d) {
            pktHeader = d;
        }

        public void SetPosition(int position) {
            pktPosition = position;
        }
    }

    public class FrameDescriptor {

        int frameInfo; // see AEDAT3.0 spec for frame event
        int startOfCaptureTimestamp;
        int endOfCaptureTimestamp;
        int startOfExposureTimestamp;
        int endOfExposureTimestamp;
        int xLength; // width
        int yLength; // height
        int xPosition; // offset of LL corner in pixels
        int yPosition; // offset of LL corner in pixels
    }

    // private EventRaw tmpEventRaw = new EventRaw();
    /**
     * This method finds the packet header.
     *
     * @param startPosition: The position
     * @param direction: The search direction, 1 is forward and 0 is backward.
     * @return: The packet header which the startPosition nearest to according
     * to the search direction.
     * @throws IOException
     */
    private PacketDescriptor searchPacketHeader(int startPosition, int direction) throws IOException {
        PacketDescriptor pkt = new PacketDescriptor();
        PacketHeader d = pkt.getPktHeader();
        int position = pkt.getPktPosition();

        int eventTypeInt;
        int currentPosition = in.position(); // store current position, guarntee the position didn't change in this function

        boolean successFlg = false;

        if ((direction != 1) && (direction != -1)) {
            log.warning("Search direction can only be 1(forward) or -1(backward!)");
            return null;
        }

        in.position(startPosition);

        while ((in.position() <= (in.limit() - PKT_HEADER_SIZE)) && (in.position() >= 0)) {
            int currentSearchPosition = in.position();
            eventTypeInt = in.getShort();
            // By default, eventTypeInt should range from 0 to 7
            if ((eventTypeInt > 7) || (eventTypeInt < 0)) {
                in.position(currentSearchPosition + direction);
                continue;
            }

            d.eventType = EventType.values()[eventTypeInt];
            d.eventSource = in.getShort();
            d.eventSize = in.getInt();
            if (d.eventSize <= 0) {
                in.position(currentSearchPosition + direction);
                continue;
            }
            d.eventTSOffset = in.getInt(); // eventoverflow

            // timestamp offset can only be 6(Configuration Event), 12 (Frame Event) or 4(other events).
            if (d.eventType == EventType.ConfigEvent) {
                if (d.eventTSOffset != 6) {
                    in.position(currentSearchPosition + direction);
                    continue;
                }
            } else if (d.eventType == EventType.FrameEvent) {
                if ((d.eventTSOffset != 12) && (d.eventTSOffset != 8)) {
                    in.position(currentSearchPosition + direction);
                    continue;
                }
            } else if (d.eventTSOffset != 4) {
                in.position(currentSearchPosition + direction);
                continue;
            }

            // This section is used to check the relationship between eventType and eventSize
            {
                if ((d.eventType == EventType.SpecialEvent) || (d.eventType == EventType.PolarityEvent)
                        || (d.eventType == EventType.SampleEvent) || (d.eventType == EventType.EarEvent)) {
                    if (d.eventSize != 8) {
                        in.position(currentSearchPosition + direction);
                        continue;
                    }
                }

                if (d.eventType == EventType.FrameEvent) {
                    if (d.eventSize < 36) {
                        in.position(currentSearchPosition + direction);
                        continue;
                    }
                }

                if (d.eventType == EventType.Imu6Event) {
                    if (d.eventSize != 36) {
                        in.position(currentSearchPosition + direction);
                        continue;
                    }
                }

                if (d.eventType == EventType.Imu9Event) {
                    if (d.eventSize != 48) {
                        in.position(currentSearchPosition + direction);
                        continue;
                    }
                }

                if (d.eventType == EventType.ConfigEvent) {
                    if (d.eventSize != 10) {
                        in.position(currentSearchPosition + direction);
                        continue;
                    }
                }
            }

            d.eventTSOverflow = in.getInt(); // eventTSOverflow
            d.eventCapacity = in.getInt(); // eventcapacity

            d.eventNumber = in.getInt(); // eventnumber
            if (d.eventNumber <= 0) {
                in.position(currentSearchPosition + direction);
                continue;
            }

            // eventCapacity is always equal to eventNumber, it can only have a different value for in-memory packets.
            // The relationship is: eventValid <= eventNumber <= eventCapacity. And eventCapacity must be at least 1.
            if (d.eventNumber > d.eventCapacity) {
                in.position(currentSearchPosition + direction);
                continue;
            }

            d.eventValid = in.getInt(); // eventValid
            if (d.eventValid < 0) {
                in.position(currentSearchPosition + direction);
                continue;
            }

            position = in.position() - PKT_HEADER_SIZE;

            if (d.eventNumber >= d.eventValid) {
                successFlg = true;
                break;
            } else { // Not succesful, move to the next/previous position to continue.
                in.position(currentSearchPosition + direction);
                continue;
            }

        }

        // This condition is to make sure the positions that start from the position bigger than in.limit() - PKT_HEADER_SIZE will skip the while loop
        // and return null directly. Sometimes, the header is found and in.position() also > in.limit() - PKT_HEADER_SIZE, so here we use successFlg to
        // distiguish them.
        if ((in.position() > (in.limit() - PKT_HEADER_SIZE)) && !successFlg) {
            in.position(currentPosition); // restore the position, because the byteBuffer in AEFileinputStream share the
            // position with in.
            return null;
        }

        pkt.SetPktHeader(d);
        pkt.SetPosition(position);

        in.position(currentPosition); // restore the position, because the byteBuffer in AEFileinputStream share the
        // position with in.
        return pkt;
    } // searchPacketHeader

    /**
     * The method is to find the current packet header which the target position
     * belongs to.
     *
     * @param targetPosition: the target position
     * @return current packet header.
     * @throws IOException
     */
    private PacketDescriptor getCurrentPkt(int targetPosition) throws IOException {

        PacketDescriptor pkt = searchPacketHeader(targetPosition, -1);

        if ((targetPosition - pkt.pktPosition) > (((pkt.pktHeader.eventSize) * (pkt.pktHeader.eventNumber)) + PKT_HEADER_SIZE)) {
            log.warning("Current position data is an invalid data, it doesn't belong to any packet!");
            return null;
        } else {<commit_msg>added more logging printout to debug incorrect parsing of AER-DAT-3.1 files<commit_after>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package net.sf.jaer.eventio;

import java.awt.Point;
import java.io.IOException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;

import eu.seebetter.ini.chips.davis.DavisBaseCamera;
import net.sf.jaer.aemonitor.AEPacketRaw;
import net.sf.jaer.aemonitor.EventRaw.EventType;
import net.sf.jaer.chip.AEChip;
import net.sf.jaer.chip.EventExtractor2D;
import net.sf.jaer.chip.RetinaExtractor;
import net.sf.jaer.event.ApsDvsEvent;
import net.sf.jaer.event.ApsDvsEvent.ReadoutType;
import net.sf.jaer.event.ApsDvsEventPacket;
import net.sf.jaer.event.EventPacket;
import net.sf.jaer.event.OutputEventIterator;

/**
 * This class parses the buffer from the data files or network streams
 * containing jAER 3.0 format data, as specified in
 * http://inilabs.com/support/software/fileformat/
 *
 * The most useful public interface for outside is the getJaer2EventBuf(), by
 * this method, the event buffer just include addr and timestamp (like jAER 2.0
 * did) will be returned. After get this buffer similar to jAER 2.0, all other
 * things will be processed by AEFileInputStream. The stream will be treated
 * like it's a jAER 2.0 buffer.
 *
 * @author <NAME>
 * @author tobi
 */
public class Jaer3BufferParser {

    private static final Logger log = Logger.getLogger("net.sf.jaer.eventio");
//	private int BUFFER_CAPACITY_BYTES = 8 * 1000000;
    private ByteBuffer in = null; // no reason to allocate here since it is copied reference from constuctor  (tobi) // ByteBuffer.allocate(BUFFER_CAPACITY_BYTES);
    // private ByteBuffer out = ByteBuffer.allocate(BUFFER_CAPACITY_BYTES);

    private final int PKT_HEADER_SIZE = 28;

    private int framePixelArrayOffset = 0; // Just for frame events and this is the origin index
    private int translatedArrayIndex = 0; // This is the correct index, in fact it's the transpose of the origin array.

    private PacketDescriptor currentPkt = new PacketDescriptor();
    private long numEvents = 0;

    /**
     * These points are the first and last pixel APS read out from the array.
     * Subclasses must set and use these values in the firstFrameAddress and
     * lastFrameAddress methods and event filters that transform the APS
     * addresses can modify these values to properly account for the order of
     * readout, e.g. in RotateFilter.
     *
     */
    protected Point apsFirstPixelReadOut = null, apsLastPixelReadOut = null;
    /**
     * The AEChip object associated with this stream. This field was added for
     * supported jAER 3.0 format files to support translating bit locations in
     * events.
     */
    private AEChip chip = null;

    /**
     * Field for decoding jaer 3.1 dvs address. Note these fields are overridden
     * by AEFileInputStream.parseFileFormatVersion. These codes get the
     * addresses from the AEDAT-3.1 data fields, which are then used to recode
     * them to the AEDAT-2.0 format used internally and by existing AEChip
     * EventExtractors, using the constants specified in
     * eu.seebetter.ini.chips.DavisChip. See
     * http://inilabs.com/support/software/fileformat/
     *
     * @see AEFileInputStream#parseFileFormatVersion(java.lang.String) - sets
     * these constants according to file type
     */
    public static int JAER3YSHIFT = 2, JAER3YMASK = 0x07FFF << JAER3YSHIFT, // ?? 3.0 is 15 bits from bits 22 to 30, 3.1 is 14 bits from bits 18 to 31.
            JAER3XSHIFT = 17, JAER3XMASK = 0x07FFF << JAER3XSHIFT, // ?? 3.0 is 15 bits from bits 12 to 21, 3.1 is 14 bits from bits from 4 to 17.
            JAER3POLSHIFT = 1, JAER3POLMASK = 1 << JAER3POLSHIFT, // , // ?? 1 bit at bit 11
            JAER3VALIDITY_BIT = 0; // marks filtered out events, 0 in the 0th bit of the first byte means invalid, 1 means valid. 
    /**
     * Field for decoding jaer 3.1 aps address
     */
    public static final int JAER3APSYSHIFT = 0, JAER3APSYMASK = 65535 << JAER3APSYSHIFT, // 16 bits from bits 16 to 31
            JAER3APSXSHIFT = 16, JAER3APSXMASK = 65535 << JAER3APSXSHIFT; // 16 bits from bits 0 to 15

    private boolean inFrameEvent = false; // TODO a flag used to represent the current event is in the frame or not.
    // The reason why we use this flag is that a whole frame events is divided into several pixels data, and current in jaer, every
    // pixel data is packed as one single complete jaer 2 event.
    private int frameCurrentEventOffset; // TODO ?? counter for something
    private boolean readOutType = false; // TODO ?? flag for something

    private static AEChip ORIGINAL_CHIP = null;
    private static EventExtractor2D ORIGINAL_EVENT_EXTRACTOR = null;

    private static Jaer3EventExtractor JAER3_EXTRACTOR = null;

    public class PacketHeader {

        EventType eventType = EventType.SpecialEvent;
        int eventSource = 0;
        int eventSize = 0;
        int eventTSOffset = 0;
        int eventTSOverflow = 0;
        int eventCapacity = 0;
        int eventNumber = 0;
        int eventValid = 0;

        @Override
        public String toString() {
            return "PacketHeader{" + "eventType=" + eventType + ", eventSource=" + eventSource + ", eventSize=" + eventSize + ", eventTSOffset=" + eventTSOffset + ", eventTSOverflow=" + eventTSOverflow + ", eventCapacity=" + eventCapacity + ", eventNumber=" + eventNumber + ", eventValid=" + eventValid + '}';
        }

    }

    public class PacketDescriptor {

        private PacketHeader pktHeader;
        private int pktPosition;

        public PacketDescriptor() {
            pktHeader = new PacketHeader();
            pktPosition = 0;
        }

        public PacketHeader getPktHeader() {
            return pktHeader;
        }

        public int getPktPosition() {
            return pktPosition;
        }

        public void setPktHeader(PacketHeader d) {
            pktHeader = d;
        }

        public void setPosition(int position) {
            pktPosition = position;
        }

        @Override
        public String toString() {
            return "PacketDescriptor{" + "pktHeader=" + pktHeader + ", pktPosition=" + pktPosition + '}';
        }
    }

    public class FrameDescriptor {

        int frameInfo; // see AEDAT3.0 spec for frame event
        int startOfCaptureTimestamp;
        int endOfCaptureTimestamp;
        int startOfExposureTimestamp;
        int endOfExposureTimestamp;
        int xLength; // width
        int yLength; // height
        int xPosition; // offset of LL corner in pixels
        int yPosition; // offset of LL corner in pixels
    }

    // private EventRaw tmpEventRaw = new EventRaw();
    /**
     * This method finds the packet header.
     *
     * @param startPosition: The position
     * @param direction: The search direction, 1 is forward and -1 is backward.
     * @return: The packet header which the startPosition nearest to according
     * to the search direction.
     * @throws IOException
     */
    private PacketDescriptor searchPacketHeader(int startPosition, int direction) throws IOException {
        PacketDescriptor pkt = new PacketDescriptor();
        PacketHeader d = pkt.getPktHeader();
        int position = pkt.getPktPosition();

        int eventTypeInt;
        int currentPosition = in.position(); // store current position, guarntee the position didn't change in this function

        boolean successFlg = false;

        if ((direction != 1) && (direction != -1)) {
            log.warning("Search direction can only be 1(forward) or -1(backward!)");
            return null;
        }

        in.position(startPosition);

        while ((in.position() <= (in.limit() - PKT_HEADER_SIZE)) && (in.position() >= 0)) {
            int currentSearchPosition = in.position();
            eventTypeInt = in.getShort();
            // By default, eventTypeInt should range from 0 to 7
            if ((eventTypeInt > 7) || (eventTypeInt < 0)) { // TODO doesn't handle POINTXD or other later events yet
                log.warning("At buffer position "+in.position()+" Event with eventType="+eventTypeInt+" which is <0 or >7; searching for next event: ");
                in.position(currentSearchPosition + direction); // TODO ?? just goes forward 1 or backward 1 byte ?? how will this help?
                continue;
            }

            d.eventType = EventType.values()[eventTypeInt];
            d.eventSource = in.getShort();
            d.eventSize = in.getInt();
            if (d.eventSize <= 0) {
                in.position(currentSearchPosition + direction);
                continue;
            }
            d.eventTSOffset = in.getInt(); // timestamp offset can only be 6(Configuration Event), 12 (Frame Event) or 4(other events).
            d.eventTSOverflow = in.getInt(); // overflow counter, using to generate 64 bit timestamp for systems that have this (not jaer, it handles big wraps in rendering)

            if (d.eventType == EventType.ConfigEvent) {
                if (d.eventTSOffset != 6) {
                    log.warning("At buffer position "+in.position()+" ConfigEvent with eventTSOffset!=6: " + d.toString());
                    in.position(currentSearchPosition + direction);
                    continue;
                }
            } else if (d.eventType == EventType.FrameEvent) {
                if ((d.eventTSOffset != 12) && (d.eventTSOffset != 8)) {
                    log.warning("At buffer position "+in.position()+" FrameEvent with eventTSOffset!=12 and !=8: " + d.toString());
                    in.position(currentSearchPosition + direction);
                    continue;
                }
            } else if (d.eventTSOffset != 4) { // other events have ts at byte 4
                log.warning("At buffer position "+in.position()+" Some other event with eventTSOffset!=4: " + d.toString());
                in.position(currentSearchPosition + direction);
                continue;
            }

            // This section is used to check the relationship between eventType and eventSize
            {
                if ((d.eventType == EventType.SpecialEvent) || (d.eventType == EventType.PolarityEvent)
                        || (d.eventType == EventType.SampleEvent) || (d.eventType == EventType.EarEvent)) {
                    if (d.eventSize != 8) { // each of these events is 8 bytes total
                        in.position(currentSearchPosition + direction);
                        continue;
                    }
                }

                if (d.eventType == EventType.FrameEvent) {
                    if (d.eventSize < 36) { // 36 bytes describe each frame in its header
                        in.position(currentSearchPosition + direction);
                        continue;
                    }
                }

                if (d.eventType == EventType.Imu6Event) {
                    if (d.eventSize != 36) {
                        in.position(currentSearchPosition + direction);
                        continue;
                    }
                }

                if (d.eventType == EventType.Imu9Event) {
                    if (d.eventSize != 48) {
                        in.position(currentSearchPosition + direction);
                        continue;
                    }
                }

                if (d.eventType == EventType.ConfigEvent) {
                    if (d.eventSize != 10) {
                        in.position(currentSearchPosition + direction);
                        continue;
                    }
                }
            }

            d.eventCapacity = in.getInt(); // eventcapacity

            d.eventNumber = in.getInt(); // eventnumber
            if (d.eventNumber <= 0) {
                in.position(currentSearchPosition + direction);
                continue;
            }

            // eventCapacity is always equal to eventNumber, it can only have a different value for in-memory packets.
            // The relationship is: eventValid <= eventNumber <= eventCapacity. And eventCapacity must be at least 1.
            if (d.eventNumber > d.eventCapacity) {
                in.position(currentSearchPosition + direction);
                continue;
            }

            d.eventValid = in.getInt(); // eventValid
            if (d.eventValid < 0) {
                in.position(currentSearchPosition + direction);
                continue;
            }

            position = in.position() - PKT_HEADER_SIZE;

            if (d.eventNumber >= d.eventValid) {
                successFlg = true;
                break;
            } else { // Not succesful, move to the next/previous position to continue.
                in.position(currentSearchPosition + direction);
                continue;
            }

        }

        // This condition is to make sure the positions that start from the position bigger than in.limit() - PKT_HEADER_SIZE will skip the while loop
        // and return null directly. Sometimes, the header is found and in.position() also > in.limit() - PKT_HEADER_SIZE, so here we use successFlg to
        // distiguish them.
        if ((in.position() > (in.limit() - PKT_HEADER_SIZE)) && !successFlg) {
            in.position(currentPosition); // restore the position, because the byteBuffer in AEFileinputStream share the
            // position with in.
            return null;
        }

        pkt.setPktHeader(d);
        pkt.setPosition(position);

        in.position(currentPosition); // restore the position, because the byteBuffer in AEFileinputStream share the
        // position with in.
        return pkt;
    } // searchPacketHeader

    /**
     * The method is to find the current packet header which the target position
     * belongs to.
     *
     * @param targetPosition: the target position
     * @return current packet header.
     * @throws IOException
     */
    private PacketDescriptor getCurrentPkt(int targetPosition) throws IOException {

        PacketDescriptor pkt = searchPacketHeader(targetPosition, -1);

        if ((targetPosition - pkt.pktPosition) > (((pkt.pktHeader.eventSize) * (pkt.pktHeader.eventNumber)) + PKT_HEADER_SIZE)) {
            log.warning("Current position data is an invalid data, it doesn't belong to any packet!");
            return null;
        } else {
{'fraction_non_alphanumeric': 0.08593581735946586, 'fraction_numerical': 0.013030368296360112, 'mean_word_length': 2.113433169423335, 'pattern_counts': {'":': 0, '<': 42, '<?xml version=': 0, '>': 20, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '817171', 'n_tokens_mistral': 7735, 'n_tokens_neox': 7193, 'n_words': 2436}