http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/ChunkHeader.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/ChunkHeader.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/ChunkHeader.java
new file mode 100644
index 0000000..7f01adf
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/ChunkHeader.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.apache.nifi.logging.ComponentLog;
+import org.apache.nifi.processors.evtx.parser.bxml.NameStringNode;
+import org.apache.nifi.processors.evtx.parser.bxml.TemplateNode;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.zip.CRC32;
+
+/**
+ * A Chunk is a self-contained group of templates, strings, and nodes
+ */
+public class ChunkHeader extends Block {
+    public static final String ELF_CHNK = "ElfChnk";
+    private final String magicString;
+    private final UnsignedLong fileFirstRecordNumber;
+    private final UnsignedLong fileLastRecordNumber;
+    private final UnsignedLong logFirstRecordNumber;
+    private final UnsignedLong logLastRecordNumber;
+    private final UnsignedInteger headerSize;
+    private final UnsignedInteger lastRecordOffset;
+    private final int nextRecordOffset;
+    private final UnsignedInteger dataChecksum;
+    private final String unused;
+    private final UnsignedInteger headerChecksum;
+    private final Map<Integer, NameStringNode> nameStrings;
+    private final Map<Integer, TemplateNode> templateNodes;
+    private final int chunkNumber;
+    private final ComponentLog log;
+    private UnsignedLong recordNumber;
+
+    public ChunkHeader(BinaryReader binaryReader, ComponentLog log, long 
headerOffset, int chunkNumber) throws IOException {
+        super(binaryReader, headerOffset);
+        this.log = log;
+        this.chunkNumber = chunkNumber;
+        CRC32 crc32 = new CRC32();
+        crc32.update(binaryReader.peekBytes(120));
+
+        magicString = binaryReader.readString(8);
+        fileFirstRecordNumber = binaryReader.readQWord();
+        fileLastRecordNumber = binaryReader.readQWord();
+        logFirstRecordNumber = binaryReader.readQWord();
+        logLastRecordNumber = binaryReader.readQWord();
+        headerSize = binaryReader.readDWord();
+        lastRecordOffset = binaryReader.readDWord();
+        nextRecordOffset = NumberUtil.intValueMax(binaryReader.readDWord(), 
Integer.MAX_VALUE, "Invalid next record offset.");
+        dataChecksum = binaryReader.readDWord();
+        unused = binaryReader.readString(68);
+
+        if (!ELF_CHNK.equals(magicString)) {
+            throw new IOException("Invalid magic string " + this);
+        }
+
+        headerChecksum = binaryReader.readDWord();
+
+        // These are included into the checksum
+        crc32.update(binaryReader.peekBytes(384));
+
+        if (crc32.getValue() != headerChecksum.longValue()) {
+            throw new IOException("Invalid checksum " + this);
+        }
+        if 
(lastRecordOffset.compareTo(UnsignedInteger.valueOf(Integer.MAX_VALUE)) > 0) {
+            throw new IOException("Last record offset too big to fit into 
signed integer");
+        }
+
+        nameStrings = new HashMap<>();
+        for (int i = 0; i < 64; i++) {
+            int offset = NumberUtil.intValueMax(binaryReader.readDWord(), 
Integer.MAX_VALUE, "Invalid offset.");
+            while (offset > 0) {
+                NameStringNode nameStringNode = new NameStringNode(new 
BinaryReader(binaryReader, offset), this);
+                nameStrings.put(offset, nameStringNode);
+                offset = 
NumberUtil.intValueMax(nameStringNode.getNextOffset(), Integer.MAX_VALUE, 
"Invalid offset.");
+            }
+        }
+
+        templateNodes = new HashMap<>();
+        for (int i = 0; i < 32; i++) {
+            int offset = NumberUtil.intValueMax(binaryReader.readDWord(), 
Integer.MAX_VALUE, "Invalid offset.");
+            while (offset > 0) {
+                int token = new BinaryReader(binaryReader, offset - 10).read();
+                if (token != 0x0c) {
+                    log.warn("Unexpected token when parsing template at offset 
" + offset);
+                    break;
+                }
+                BinaryReader templateReader = new BinaryReader(binaryReader, 
offset - 4);
+                int pointer = 
NumberUtil.intValueMax(templateReader.readDWord(), Integer.MAX_VALUE, "Invalid 
pointer.");
+                if (offset != pointer) {
+                    log.warn("Invalid pointer when parsing template at offset 
" + offset);
+                    break;
+                }
+                TemplateNode templateNode = new TemplateNode(templateReader, 
this);
+                templateNodes.put(offset, templateNode);
+                offset = templateNode.getNextOffset();
+            }
+        }
+        crc32 = new CRC32();
+        crc32.update(binaryReader.peekBytes(nextRecordOffset - 512));
+        if (crc32.getValue() != dataChecksum.longValue()) {
+            throw new IOException("Invalid data checksum " + this);
+        }
+        recordNumber = fileFirstRecordNumber.minus(UnsignedLong.ONE);
+    }
+
+    public NameStringNode addNameStringNode(int offset, BinaryReader 
binaryReader) throws IOException {
+        NameStringNode nameStringNode = new NameStringNode(binaryReader, this);
+        nameStrings.put(offset, nameStringNode);
+        return nameStringNode;
+    }
+
+    public TemplateNode addTemplateNode(int offset, BinaryReader binaryReader) 
throws IOException {
+        TemplateNode templateNode = new TemplateNode(binaryReader, this);
+        templateNodes.put(offset, templateNode);
+        return templateNode;
+    }
+
+    public TemplateNode getTemplateNode(int offset) {
+        return templateNodes.get(offset);
+    }
+
+    @Override
+    public String toString() {
+        return "ChunkHeader{" +
+                "magicString='" + magicString + '\'' +
+                ", fileFirstRecordNumber=" + fileFirstRecordNumber +
+                ", fileLastRecordNumber=" + fileLastRecordNumber +
+                ", logFirstRecordNumber=" + logFirstRecordNumber +
+                ", logLastRecordNumber=" + logLastRecordNumber +
+                ", headerSize=" + headerSize +
+                ", lastRecordOffset=" + lastRecordOffset +
+                ", nextRecordOffset=" + nextRecordOffset +
+                ", dataChecksum=" + dataChecksum +
+                ", unused='" + unused + '\'' +
+                ", headerChecksum=" + headerChecksum +
+                '}';
+    }
+
+    public boolean hasNext() {
+        return fileLastRecordNumber.compareTo(recordNumber) > 0;
+    }
+
+    public String getString(int offset) {
+        NameStringNode nameStringNode = nameStrings.get(offset);
+        if (nameStringNode == null) {
+            return null;
+        }
+        return nameStringNode.getString();
+    }
+
+    @VisibleForTesting
+    Map<Integer, NameStringNode> getNameStrings() {
+        return Collections.unmodifiableMap(nameStrings);
+    }
+
+    @VisibleForTesting
+    Map<Integer, TemplateNode> getTemplateNodes() {
+        return Collections.unmodifiableMap(templateNodes);
+    }
+
+    public int getChunkNumber() {
+        return chunkNumber;
+    }
+
+    public Record next() throws IOException {
+        if (!hasNext()) {
+            return null;
+        }
+        try {
+            Record record = new Record(getBinaryReader(), this);
+            recordNumber = record.getRecordNum();
+            return record;
+        } catch (IOException e) {
+            recordNumber = fileLastRecordNumber;
+            throw e;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/FileHeader.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/FileHeader.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/FileHeader.java
new file mode 100644
index 0000000..8610fe9
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/FileHeader.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser;
+
+import com.google.common.primitives.UnsignedInteger;
+import com.google.common.primitives.UnsignedLong;
+import org.apache.nifi.logging.ComponentLog;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.CRC32;
+
+/**
+ * FileHeader at the top of an Evtx file has metadata about the chunks of the 
file as well as top-level metadata
+ */
+public class FileHeader extends Block {
+    public static final int CHUNK_SIZE = 65536;
+    public static final String ELF_FILE = "ElfFile";
+    private final String magicString;
+    private final UnsignedLong oldestChunk;
+    private final UnsignedLong currentChunkNumber;
+    private final UnsignedLong nextRecordNumber;
+    private final UnsignedInteger headerSize;
+    private final int minorVersion;
+    private final int majorVersion;
+    private final int headerChunkSize;
+    private final int chunkCount;
+    private final String unused1;
+    private final UnsignedInteger flags;
+    private final UnsignedInteger checksum;
+    private final InputStream inputStream;
+    private final ComponentLog log;
+    private long currentOffset;
+    private int count = 1;
+
+    public FileHeader(InputStream inputStream, ComponentLog log) throws 
IOException {
+        super(new BinaryReader(inputStream, 4096));
+        this.log = log;
+        // Bytes will be checksummed
+        BinaryReader binaryReader = getBinaryReader();
+        CRC32 crc32 = new CRC32();
+        crc32.update(binaryReader.peekBytes(120));
+
+        magicString = binaryReader.readString(8);
+        if (!ELF_FILE.equals(magicString)) {
+            throw new IOException("Invalid magic string. Expected " + ELF_FILE 
+ " got " + magicString);
+        }
+        oldestChunk = binaryReader.readQWord();
+        currentChunkNumber = binaryReader.readQWord();
+        nextRecordNumber = binaryReader.readQWord();
+        headerSize = binaryReader.readDWord();
+        minorVersion = binaryReader.readWord();
+        majorVersion = binaryReader.readWord();
+        headerChunkSize = binaryReader.readWord();
+        chunkCount = binaryReader.readWord();
+        unused1 = binaryReader.readString(76);
+
+        // Not part of checksum
+        flags = binaryReader.readDWord();
+        checksum = binaryReader.readDWord();
+
+        if (crc32.getValue() != checksum.longValue()) {
+            throw new IOException("Invalid checksum");
+        }
+        NumberUtil.intValueExpected(minorVersion, 1, "Invalid minor version.");
+        NumberUtil.intValueExpected(majorVersion, 3, "Invalid minor version.");
+        NumberUtil.intValueExpected(headerChunkSize, 4096, "Invalid header 
chunk size.");
+        this.inputStream = inputStream;
+        currentOffset = 4096;
+
+        init();
+    }
+
+    @Override
+    protected int getHeaderLength() {
+        return 4096;
+    }
+
+    public String getMagicString() {
+        return magicString;
+    }
+
+    public UnsignedLong getOldestChunk() {
+        return oldestChunk;
+    }
+
+    public UnsignedLong getCurrentChunkNumber() {
+        return currentChunkNumber;
+    }
+
+    public UnsignedLong getNextRecordNumber() {
+        return nextRecordNumber;
+    }
+
+    public UnsignedInteger getHeaderSize() {
+        return headerSize;
+    }
+
+    public int getMinorVersion() {
+        return minorVersion;
+    }
+
+    public int getMajorVersion() {
+        return majorVersion;
+    }
+
+    public int getHeaderChunkSize() {
+        return headerChunkSize;
+    }
+
+    public int getChunkCount() {
+        return chunkCount;
+    }
+
+    public String getUnused1() {
+        return unused1;
+    }
+
+    public UnsignedInteger getFlags() {
+        return flags;
+    }
+
+    public UnsignedInteger getChecksum() {
+        return checksum;
+    }
+
+    /**
+     * Tests whether there are more chunks
+     * @return true iff there are chunks left
+     */
+    public boolean hasNext() {
+        return count < chunkCount;
+    }
+
+    /**
+     * Returns the next chunkHeader or null if there are no more
+     *
+     * @return chunkHeader
+     * @throws MalformedChunkException if there is an error reading the chunk 
header
+     * @throws IOException if there is an exception creating the BinaryReader
+     */
+    public ChunkHeader next() throws MalformedChunkException, IOException {
+        if (count <= chunkCount) {
+            long currentOffset = this.currentOffset;
+            this.currentOffset += CHUNK_SIZE;
+            BinaryReader binaryReader = new BinaryReader(inputStream, 
CHUNK_SIZE);
+            try {
+                return new ChunkHeader(binaryReader, log, currentOffset, 
count++);
+            } catch (IOException e) {
+                throw new MalformedChunkException("Malformed chunk, unable to 
parse", e, currentOffset, count - 1, binaryReader.getBytes());
+            }
+        } else {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/FileHeaderFactory.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/FileHeaderFactory.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/FileHeaderFactory.java
new file mode 100644
index 0000000..a2dbbeb
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/FileHeaderFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser;
+
+import org.apache.nifi.logging.ComponentLog;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public interface FileHeaderFactory {
+    FileHeader create(InputStream inputStream, ComponentLog componentLog) 
throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/MalformedChunkException.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/MalformedChunkException.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/MalformedChunkException.java
new file mode 100644
index 0000000..ab67208
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/MalformedChunkException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser;
+
+/**
+ * Exception when a chunk is malformed.
+ * Chunks are independent within the file so we should be able to safely 
continue processing the remaining chunks.
+ */
+public class MalformedChunkException extends Exception {
+    private final long offset;
+    private final int chunkNum;
+    private byte[] badChunk;
+
+    public MalformedChunkException(String message, Throwable cause, long 
offset, int chunkNum, byte[] badChunk) {
+        super(message, cause);
+        this.offset = offset;
+        this.chunkNum = chunkNum;
+        this.badChunk = badChunk;
+    }
+
+    public byte[] getBadChunk() {
+        return badChunk;
+    }
+
+    public int getChunkNum() {
+        return chunkNum;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/NumberUtil.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/NumberUtil.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/NumberUtil.java
new file mode 100644
index 0000000..8f5aeb3
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/NumberUtil.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser;
+
+import com.google.common.primitives.UnsignedInteger;
+
+import java.io.IOException;
+
+/**
+ * Util methods for conveniently checking numbers
+ */
+public class NumberUtil {
+    public static final String EXPECTED_TEXT = " Expected %s got %s.";
+
+    /**
+     * Throws an exception if the Number isn't what was expected, returning 
the number if it was
+     *
+     * @param number       number
+     * @param expected     expected value
+     * @param errorMessage error message (can be Java format string)
+     * @param args         args for error message format string
+     * @return the value if it was what was expected
+     * @throws IOException if the value isn't what was expected
+     */
+    public static int intValueExpected(Number number, int expected, String 
errorMessage, Object... args) throws IOException {
+        int result = number.intValue();
+        if (result != expected) {
+            throw createException(errorMessage, args, expected, result);
+        }
+        return result;
+    }
+
+    /**
+     * Throws an exception if the UnsignedInteger is greater than a given int, 
returning the int value otherwise
+     *
+     * @param unsignedInteger the number
+     * @param max             the maximum value
+     * @param errorMessage    error message (can be Java format string)
+     * @param args            args for error message format string
+     * @return the value
+     * @throws IOException if the value is greater than max
+     */
+    public static int intValueMax(UnsignedInteger unsignedInteger, int max, 
String errorMessage, Object... args) throws IOException {
+        if (unsignedInteger.compareTo(UnsignedInteger.valueOf(max)) > 0) {
+            throw createException(errorMessage, args, "< " + max, 
unsignedInteger);
+        }
+        return unsignedInteger.intValue();
+    }
+
+    private static IOException createException(String errorMessage, Object[] 
args, Object expected, Object actual) {
+        return new IOException(String.format(errorMessage, args) + 
String.format(EXPECTED_TEXT, expected, actual));
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/Record.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/Record.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/Record.java
new file mode 100644
index 0000000..4580c9f
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/Record.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser;
+
+import com.google.common.primitives.UnsignedLong;
+import org.apache.nifi.processors.evtx.parser.bxml.RootNode;
+
+import java.io.IOException;
+import java.util.Date;
+
+/**
+ * Individual event, pretty much a wrapper for the RootNode
+ */
+public class Record extends Block {
+    private final int magicNumber;
+    private final int size;
+    private final UnsignedLong recordNum;
+    private final Date timestamp;
+    private final RootNode rootNode;
+    private final int size2;
+
+    public Record(BinaryReader binaryReader, ChunkHeader chunkHeader) throws 
IOException {
+        super(binaryReader, chunkHeader.getOffset() + 
binaryReader.getPosition());
+        magicNumber = NumberUtil.intValueExpected(binaryReader.readDWord(), 
10794, "Invalid magic number.");
+        size = NumberUtil.intValueMax(binaryReader.readDWord(), 0x10000, 
"Invalid size.");
+        recordNum = binaryReader.readQWord();
+        timestamp = binaryReader.readFileTime();
+        rootNode = new RootNode(binaryReader, chunkHeader, null);
+        int desiredPosition = getInitialPosition() + size - 4;
+        int skipAmount = desiredPosition - binaryReader.getPosition();
+        if (skipAmount > 0) {
+            binaryReader.skip(skipAmount);
+        }
+        size2 = NumberUtil.intValueExpected(binaryReader.readDWord(), size, 
"Size 2 doesn't match.");
+    }
+
+    @Override
+    public String toString() {
+        return "Record{" +
+                "magicNumber=" + magicNumber +
+                ", size=" + size +
+                ", recordNum=" + recordNum +
+                ", timestamp=" + timestamp +
+                ", rootNode=" + rootNode +
+                ", size2=" + size2 +
+                '}';
+    }
+
+    public UnsignedLong getRecordNum() {
+        return recordNum;
+    }
+
+    public RootNode getRootNode() {
+        return rootNode;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/AttributeNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/AttributeNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/AttributeNode.java
new file mode 100644
index 0000000..10aef94
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/AttributeNode.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+
+/**
+ * Node representing an xml attribute
+ */
+public class AttributeNode extends BxmlNodeWithTokenAndString {
+    public AttributeNode(BinaryReader binaryReader, ChunkHeader chunkHeader, 
BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        init();
+    }
+
+    @Override
+    protected int getMaxChildren() {
+        return 1;
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+
+    public String getAttributeName() {
+        return getStringValue();
+    }
+
+    public BxmlNode getValue() {
+        return getChildren().get(0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNode.java
new file mode 100644
index 0000000..ec25d82
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNode.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.Block;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Base class that helps initialization by creating children, skipping bytes 
where necessary
+ */
+public abstract class BxmlNode extends Block {
+    public static final int END_OF_STREAM_TOKEN = 0x00;
+    public static final int OPEN_START_ELEMENT_TOKEN = 0x01;
+    public static final int CLOSE_START_ELEMENT_TOKEN = 0x02;
+    public static final int CLOSE_EMPTY_ELEMENT_TOKEN = 0x03;
+    public static final int CLOSE_ELEMENT_TOKEN = 0x04;
+    public static final int VALUE_TOKEN = 0x05;
+    public static final int ATTRIBUTE_TOKEN = 0x06;
+    public static final int C_DATA_SECTION_TOKEN = 0x07;
+    public static final int ENTITY_REFERENCE_TOKEN = 0x08;
+    public static final int PROCESSING_INSTRUCTION_TARGET_TOKEN = 0x0A;
+    public static final int PROCESSING_INSTRUCTION_DATA_TOKEN = 0x0B;
+    public static final int TEMPLATE_INSTANCE_TOKEN = 0x0C;
+    public static final int NORMAL_SUBSTITUTION_TOKEN = 0x0D;
+    public static final int CONDITIONAL_SUBSTITUTION_TOKEN = 0x0E;
+    public static final int START_OF_STREAM_TOKEN = 0x0F;
+
+    private static final BxmlNodeFactory[] factories = new 
BxmlNodeFactory[]{EndOfStreamNode::new, OpenStartElementNode::new,
+            CloseStartElementNode::new, CloseEmptyElementNode::new, 
CloseElementNode::new, ValueNode::new, AttributeNode::new,
+            CDataSectionNode::new, null, EntityReferenceNode::new, 
ProcessingInstructionTargetNode::new,
+            ProcessingInstructionDataNode::new, TemplateInstanceNode::new, 
NormalSubstitutionNode::new,
+            ConditionalSubstitutionNode::new, StreamStartNode::new};
+    private final ChunkHeader chunkHeader;
+    private final BxmlNode parent;
+    protected List<BxmlNode> children;
+    private boolean hasEndOfStream = false;
+
+    protected BxmlNode(BinaryReader binaryReader, ChunkHeader chunkHeader, 
BxmlNode parent) {
+        super(binaryReader, chunkHeader.getOffset() + 
binaryReader.getPosition());
+        this.chunkHeader = chunkHeader;
+        this.parent = parent;
+        hasEndOfStream = false;
+    }
+
+    @Override
+    protected void init(boolean shouldClearBinaryReader) throws IOException {
+        super.init(false);
+        children = Collections.unmodifiableList(initChildren());
+        if (shouldClearBinaryReader) {
+            clearBinaryReader();
+        }
+    }
+
+    protected List<BxmlNode> initChildren() throws IOException {
+        BinaryReader binaryReader = getBinaryReader();
+        List<BxmlNode> result = new ArrayList<>();
+        int maxChildren = getMaxChildren();
+        int[] endTokens = getEndTokens();
+        for (int i = 0; i < maxChildren; i++) {
+            // Masking flags for location of factory
+            int token = binaryReader.peek();
+            int factoryIndex = token & 0x0F;
+            if (factoryIndex > factories.length - 1) {
+                throw new IOException("Invalid token " + factoryIndex);
+            }
+            BxmlNodeFactory factory = factories[factoryIndex];
+            if (factory == null) {
+                throw new IOException("Invalid token " + factoryIndex);
+            }
+            BxmlNode bxmlNode = factory.create(binaryReader, chunkHeader, 
this);
+            result.add(bxmlNode);
+            if (bxmlNode.hasEndOfStream() || bxmlNode instanceof 
EndOfStreamNode) {
+                hasEndOfStream = true;
+                break;
+            }
+            if (Arrays.binarySearch(endTokens, factoryIndex) >= 0) {
+                break;
+            }
+        }
+        return result;
+    }
+
+    protected int getMaxChildren() {
+        return Integer.MAX_VALUE;
+    }
+
+    protected int[] getEndTokens() {
+        return new int[]{END_OF_STREAM_TOKEN};
+    }
+
+    public List<BxmlNode> getChildren() {
+        if (!isInitialized()) {
+            throw new RuntimeException("Need to initialize children");
+        }
+        return children;
+    }
+
+    public ChunkHeader getChunkHeader() {
+        return chunkHeader;
+    }
+
+    public BxmlNode getParent() {
+        return parent;
+    }
+
+    public boolean hasEndOfStream() {
+        return hasEndOfStream;
+    }
+
+    public abstract void accept(BxmlNodeVisitor bxmlNodeVisitor) throws 
IOException;
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeFactory.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeFactory.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeFactory.java
new file mode 100644
index 0000000..2631fec
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+
+public interface BxmlNodeFactory {
+    BxmlNode create(BinaryReader binaryReader, ChunkHeader chunkHeader, 
BxmlNode parent) throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithToken.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithToken.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithToken.java
new file mode 100644
index 0000000..0db4ed0
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithToken.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+
+/**
+ * Common supertype for nodes that begin with a token
+ */
+public abstract class BxmlNodeWithToken extends BxmlNode {
+    private final int token;
+
+    public BxmlNodeWithToken(BinaryReader binaryReader, ChunkHeader 
chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        token = binaryReader.read();
+    }
+
+    public int getToken() {
+        return token;
+    }
+
+    public int getFlags() {
+        return getToken() >> 4;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenAndString.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenAndString.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenAndString.java
new file mode 100644
index 0000000..d8d937f
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/BxmlNodeWithTokenAndString.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+import org.apache.nifi.processors.evtx.parser.NumberUtil;
+
+import java.io.IOException;
+
+/**
+ * Common supertype for nodes that have a token first and then a 
NameStringNode reference
+ */
+public abstract class BxmlNodeWithTokenAndString extends BxmlNodeWithToken {
+    private final int stringOffset;
+    private final String value;
+    private final int tagLength;
+
+    public BxmlNodeWithTokenAndString(BinaryReader binaryReader, ChunkHeader 
chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        stringOffset = NumberUtil.intValueMax(binaryReader.readDWord(), 
Integer.MAX_VALUE, "Invalid string offset.");
+        int tagLength = getBaseTagLength();
+        if (stringOffset > getOffset() - chunkHeader.getOffset()) {
+            int initialPosition = binaryReader.getPosition();
+            NameStringNode nameStringNode = 
chunkHeader.addNameStringNode(stringOffset, binaryReader);
+            tagLength += binaryReader.getPosition() - initialPosition;
+            value = nameStringNode.getString();
+        } else {
+            value = chunkHeader.getString(stringOffset);
+        }
+        this.tagLength = tagLength;
+    }
+
+    @Override
+    protected int getHeaderLength() {
+        return tagLength;
+    }
+
+    protected int getBaseTagLength() {
+        return 5;
+    }
+
+    public int getStringOffset() {
+        return stringOffset;
+    }
+
+    public String getStringValue() {
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CDataSectionNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CDataSectionNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CDataSectionNode.java
new file mode 100644
index 0000000..06022cd
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CDataSectionNode.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * CData section
+ */
+public class CDataSectionNode extends BxmlNodeWithToken {
+    private final int stringLength;
+    private final String cdata;
+
+    public CDataSectionNode(BinaryReader binaryReader, ChunkHeader 
chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        if (getFlags() != 0) {
+            throw new IOException("Invalid flags");
+        }
+        if (getToken() != C_DATA_SECTION_TOKEN) {
+            throw new IOException("Invalid CDataSectionToken");
+        }
+        stringLength = binaryReader.readWord();
+        cdata = binaryReader.readWString(stringLength - 2);
+        init();
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    public String getCdata() {
+        return cdata;
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseElementNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseElementNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseElementNode.java
new file mode 100644
index 0000000..7b2706d
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseElementNode.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Close tag
+ */
+public class CloseElementNode extends BxmlNodeWithToken {
+    public CloseElementNode(BinaryReader binaryReader, ChunkHeader 
chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        if ((getFlags() & 0x0F) != 0) {
+            throw new IOException("Invalid flag");
+        }
+        init();
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseEmptyElementNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseEmptyElementNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseEmptyElementNode.java
new file mode 100644
index 0000000..8b22497
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseEmptyElementNode.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Close tag
+ */
+public class CloseEmptyElementNode extends BxmlNodeWithToken {
+    public CloseEmptyElementNode(BinaryReader binaryReader, ChunkHeader 
chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        init();
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseStartElementNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseStartElementNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseStartElementNode.java
new file mode 100644
index 0000000..1466718
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/CloseStartElementNode.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Close tag
+ */
+public class CloseStartElementNode extends BxmlNodeWithToken {
+    public CloseStartElementNode(BinaryReader binaryReader, ChunkHeader 
chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        if ((getFlags() & 0x0F) != 0) {
+            throw new IOException("Invalid flag");
+        }
+        init();
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ConditionalSubstitutionNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ConditionalSubstitutionNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ConditionalSubstitutionNode.java
new file mode 100644
index 0000000..e9c7358
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ConditionalSubstitutionNode.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Template node marked for substitution with the value the root node has at 
the given index
+ */
+public class ConditionalSubstitutionNode extends BxmlNodeWithToken {
+    private final int index;
+    private final int type;
+
+    public ConditionalSubstitutionNode(BinaryReader binaryReader, ChunkHeader 
chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        index = binaryReader.readWord();
+        type = binaryReader.read();
+        if (getFlags() != 0) {
+            throw new IOException("Invalid flags");
+        }
+        if (getToken() != CONDITIONAL_SUBSTITUTION_TOKEN) {
+            throw new IOException("Invalid token");
+        }
+        init();
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/EndOfStreamNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/EndOfStreamNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/EndOfStreamNode.java
new file mode 100644
index 0000000..25b8298
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/EndOfStreamNode.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Node denoting the end of a template
+ */
+public class EndOfStreamNode extends BxmlNodeWithToken {
+    public EndOfStreamNode(BinaryReader binaryReader, ChunkHeader chunkHeader, 
BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        init();
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/EntityReferenceNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/EntityReferenceNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/EntityReferenceNode.java
new file mode 100644
index 0000000..868651a
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/EntityReferenceNode.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * An escape string node
+ */
+public class EntityReferenceNode extends BxmlNodeWithTokenAndString {
+    public EntityReferenceNode(BinaryReader binaryReader, ChunkHeader 
chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        init();
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+
+    public String getValue() {
+        return "&" + getStringValue() + ";";
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/NameStringNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/NameStringNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/NameStringNode.java
new file mode 100644
index 0000000..b92f603
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/NameStringNode.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import com.google.common.primitives.UnsignedInteger;
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * The strings are stored separately to conserve space
+ */
+public class NameStringNode extends BxmlNode {
+    private final UnsignedInteger nextOffset;
+    private final int hash;
+    private final String string;
+    private final int stringLength;
+
+    public NameStringNode(BinaryReader binaryReader, ChunkHeader chunkHeader) 
throws IOException {
+        super(binaryReader, chunkHeader, null);
+        nextOffset = binaryReader.readDWord();
+        hash = binaryReader.readWord();
+        stringLength = binaryReader.readWord();
+        string = binaryReader.readWString(stringLength);
+        binaryReader.skip(2);
+        init();
+    }
+
+    public UnsignedInteger getNextOffset() {
+        return nextOffset;
+    }
+
+    public int getHash() {
+        return hash;
+    }
+
+    public String getString() {
+        return string;
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/NormalSubstitutionNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/NormalSubstitutionNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/NormalSubstitutionNode.java
new file mode 100644
index 0000000..b8e0631
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/NormalSubstitutionNode.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Template node marked for substitution with the value the root node has at 
the given index
+ */
+public class NormalSubstitutionNode extends BxmlNodeWithToken {
+    private final int index;
+    private final int type;
+
+    public NormalSubstitutionNode(BinaryReader binaryReader, ChunkHeader 
chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        index = binaryReader.readWord();
+        type = binaryReader.read();
+        if (getFlags() != 0) {
+            throw new IOException("Invalid flags");
+        }
+        if (getToken() != NORMAL_SUBSTITUTION_TOKEN) {
+            throw new IOException("Invalid token");
+        }
+        init();
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/OpenStartElementNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/OpenStartElementNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/OpenStartElementNode.java
new file mode 100644
index 0000000..55e54eb
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/OpenStartElementNode.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import com.google.common.primitives.UnsignedInteger;
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+import org.apache.nifi.processors.evtx.parser.NumberUtil;
+
+import java.io.IOException;
+
+/**
+ * Open tag in the template xml
+ */
+public class OpenStartElementNode extends BxmlNodeWithToken {
+    private final int unknown;
+    private final UnsignedInteger size;
+    private final int stringOffset;
+    private final String tagName;
+    private final int tagLength;
+
+    public OpenStartElementNode(BinaryReader binaryReader, ChunkHeader 
chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        if ((getFlags() & 0x0b) != 0) {
+            throw new IOException("Invalid flag detected");
+        }
+        unknown = binaryReader.readWord();
+        size = binaryReader.readDWord();
+        stringOffset = NumberUtil.intValueMax(binaryReader.readDWord(), 
Integer.MAX_VALUE, "Invalid string offset.");
+        int tagLength = 11;
+        if ((getFlags() & 0x04) > 0) {
+            tagLength += 4;
+        }
+        String string = getChunkHeader().getString(stringOffset);
+        if (stringOffset > getOffset() - chunkHeader.getOffset()) {
+            int initialPosition = binaryReader.getPosition();
+            NameStringNode nameStringNode = 
chunkHeader.addNameStringNode(stringOffset, binaryReader);
+            tagLength += binaryReader.getPosition() - initialPosition;
+            tagName = nameStringNode.getString();
+        } else {
+            tagName = string;
+        }
+        this.tagLength = tagLength;
+        init();
+    }
+
+    public String getTagName() {
+        return tagName;
+    }
+
+    @Override
+    protected int getHeaderLength() {
+        return tagLength;
+    }
+
+    @Override
+    protected int[] getEndTokens() {
+        return new int[]{CLOSE_EMPTY_ELEMENT_TOKEN, CLOSE_ELEMENT_TOKEN};
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ProcessingInstructionDataNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ProcessingInstructionDataNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ProcessingInstructionDataNode.java
new file mode 100644
index 0000000..1583ad0
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ProcessingInstructionDataNode.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+public class ProcessingInstructionDataNode extends BxmlNodeWithToken {
+    private final int stringLength;
+    private final int tagLength;
+    private final String data;
+
+    public ProcessingInstructionDataNode(BinaryReader binaryReader, 
ChunkHeader chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        stringLength = binaryReader.readWord();
+        tagLength = 3 + (2 * stringLength);
+        if (stringLength > 0) {
+            data = binaryReader.readWString(stringLength);
+        } else {
+            data = "";
+        }
+        init();
+    }
+
+    public String getValue() {
+        return data + "?>";
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ProcessingInstructionTargetNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ProcessingInstructionTargetNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ProcessingInstructionTargetNode.java
new file mode 100644
index 0000000..c47274b
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/ProcessingInstructionTargetNode.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+public class ProcessingInstructionTargetNode extends 
BxmlNodeWithTokenAndString {
+    public ProcessingInstructionTargetNode(BinaryReader binaryReader, 
ChunkHeader chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        init();
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+
+    public String getValue() {
+        return "<?" + super.getStringValue();
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/RootNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/RootNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/RootNode.java
new file mode 100644
index 0000000..23108de
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/RootNode.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+import org.apache.nifi.processors.evtx.parser.NumberUtil;
+import org.apache.nifi.processors.evtx.parser.bxml.value.VariantTypeNode;
+import 
org.apache.nifi.processors.evtx.parser.bxml.value.VariantTypeNodeFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Node that contains children and substitutions
+ */
+public class RootNode extends BxmlNode {
+    private final int substitutionCount;
+    private final List<VariantTypeNode> substitutions;
+
+    public RootNode(BinaryReader binaryReader, ChunkHeader chunkHeader, 
BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        init();
+        substitutionCount = NumberUtil.intValueMax(binaryReader.readDWord(), 
Integer.MAX_VALUE, "Invalid substitution count.");
+        List<VariantTypeSizeAndFactory> substitutionVariantFactories = new 
ArrayList<>(substitutionCount);
+        for (long i = 0; i < substitutionCount; i++) {
+            try {
+                int substitionSize = binaryReader.readWord();
+                int substitutionType = binaryReader.readWord();
+                substitutionVariantFactories.add(new 
VariantTypeSizeAndFactory(substitionSize, 
ValueNode.factories.get(substitutionType)));
+            } catch (Exception e) {
+                throw new IOException(e);
+            }
+        }
+        List<VariantTypeNode> substitutions = new ArrayList<>();
+        for (VariantTypeSizeAndFactory substitutionVariantFactory : 
substitutionVariantFactories) {
+            
substitutions.add(substitutionVariantFactory.factory.create(binaryReader, 
chunkHeader, this, substitutionVariantFactory.size));
+        }
+        this.substitutions = Collections.unmodifiableList(substitutions);
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+
+    public List<VariantTypeNode> getSubstitutions() {
+        return substitutions;
+    }
+
+    @Override
+    public String toString() {
+        return "RootNode{" + getChildren() + "}";
+    }
+
+    public class VariantTypeSizeAndFactory {
+        private final int size;
+        private final VariantTypeNodeFactory factory;
+
+        public VariantTypeSizeAndFactory(int size, VariantTypeNodeFactory 
factory) {
+            this.size = size;
+            this.factory = factory;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/StreamStartNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/StreamStartNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/StreamStartNode.java
new file mode 100644
index 0000000..cda5669
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/StreamStartNode.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+import org.apache.nifi.processors.evtx.parser.NumberUtil;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Node denoting the beginning of a stream (generally present before the 
TemplateInstanceNode)
+ */
+public class StreamStartNode extends BxmlNodeWithToken {
+    private final int unknown;
+    private final int unknown2;
+
+    public StreamStartNode(BinaryReader binaryReader, ChunkHeader chunkHeader, 
BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        if (getFlags() != 0) {
+            throw new IOException("Invalid flags");
+        }
+        if (getToken() != START_OF_STREAM_TOKEN) {
+            throw new IOException("Invalid token " + getToken());
+        }
+        unknown = NumberUtil.intValueExpected(binaryReader.read(), 1, 
"Unexpected value for unknown field.");
+        unknown2 = NumberUtil.intValueExpected(binaryReader.readWord(), 1, 
"Unexpected value for unknown field 2");
+        init();
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/TemplateInstanceNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/TemplateInstanceNode.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/TemplateInstanceNode.java
new file mode 100644
index 0000000..0bfa417
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/TemplateInstanceNode.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.nifi.processors.evtx.parser.bxml;
+
+import com.google.common.primitives.UnsignedInteger;
+import org.apache.nifi.processors.evtx.parser.BinaryReader;
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+import org.apache.nifi.processors.evtx.parser.NumberUtil;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Instance of a Template
+ */
+public class TemplateInstanceNode extends BxmlNodeWithToken {
+
+    private final int unknown;
+    private final UnsignedInteger templateId;
+    private final int templateOffset;
+    private final boolean isResident;
+    private final TemplateNode templateNode;
+    private final int templateLength;
+
+    public TemplateInstanceNode(BinaryReader binaryReader, ChunkHeader 
chunkHeader, BxmlNode parent) throws IOException {
+        super(binaryReader, chunkHeader, parent);
+        unknown = binaryReader.read();
+        templateId = binaryReader.readDWord();
+        templateOffset = NumberUtil.intValueMax(binaryReader.readDWord(), 
Integer.MAX_VALUE, "Invalid template offset.");
+        if (templateOffset > getOffset() - chunkHeader.getOffset()) {
+            isResident = true;
+            int initialPosition = binaryReader.getPosition();
+            templateNode = chunkHeader.addTemplateNode(templateOffset, 
binaryReader);
+            templateLength = binaryReader.getPosition() - initialPosition;
+        } else {
+            isResident = false;
+            templateNode = chunkHeader.getTemplateNode(templateOffset);
+            templateLength = 0;
+        }
+
+        if (templateNode != null && 
!templateId.equals(templateNode.getTemplateId())) {
+            throw new IOException("Invalid template id");
+        }
+        init();
+    }
+
+    @Override
+    protected int getHeaderLength() {
+        return 10 + templateLength;
+    }
+
+    public TemplateNode getTemplateNode() {
+        return templateNode;
+    }
+
+    @Override
+    protected List<BxmlNode> initChildren() throws IOException {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public boolean hasEndOfStream() {
+        return super.hasEndOfStream() || templateNode.hasEndOfStream();
+    }
+
+    @Override
+    public void accept(BxmlNodeVisitor bxmlNodeVisitor) throws IOException {
+        bxmlNodeVisitor.visit(this);
+    }
+}

Reply via email to