NIFI-1975 - Processor for parsing evtx files

Signed-off-by: Matt Burgess <[email protected]>

This closes #492


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/a5fecda5
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/a5fecda5
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/a5fecda5

Branch: refs/heads/master
Commit: a5fecda5a2ffb35e21d950aa19a07127e19a419e
Parents: 1c22bc0
Author: Bryan Rosander <[email protected]>
Authored: Fri May 27 10:56:02 2016 -0400
Committer: Matt Burgess <[email protected]>
Committed: Thu Jun 9 12:07:00 2016 -0400

----------------------------------------------------------------------
 NOTICE                                          |   5 +
 nifi-assembly/NOTICE                            |   6 +
 nifi-assembly/pom.xml                           |   5 +
 .../nifi-evtx-bundle/nifi-evtx-nar/pom.xml      |  40 ++
 .../src/main/resources/META-INF/LICENSE         | 209 ++++++++
 .../src/main/resources/META-INF/NOTICE          |  36 ++
 .../nifi-evtx-processors/pom.xml                |  68 +++
 .../processors/evtx/MalformedChunkHandler.java  |  43 ++
 .../apache/nifi/processors/evtx/ParseEvtx.java  | 290 +++++++++++
 .../nifi/processors/evtx/ResultProcessor.java   |  47 ++
 .../nifi/processors/evtx/RootNodeHandler.java   |  27 ++
 .../processors/evtx/RootNodeHandlerFactory.java |  25 +
 .../processors/evtx/XmlBxmlNodeVisitor.java     | 190 ++++++++
 .../evtx/XmlBxmlNodeVisitorFactory.java         |  27 ++
 .../processors/evtx/XmlRootNodeHandler.java     |  83 ++++
 .../processors/evtx/parser/BinaryReader.java    | 294 ++++++++++++
 .../nifi/processors/evtx/parser/Block.java      |  84 ++++
 .../processors/evtx/parser/BxmlNodeVisitor.java | 121 +++++
 .../processors/evtx/parser/ChunkHeader.java     | 199 ++++++++
 .../nifi/processors/evtx/parser/FileHeader.java | 171 +++++++
 .../evtx/parser/FileHeaderFactory.java          |  27 ++
 .../evtx/parser/MalformedChunkException.java    |  43 ++
 .../nifi/processors/evtx/parser/NumberUtil.java |  68 +++
 .../nifi/processors/evtx/parser/Record.java     |  71 +++
 .../evtx/parser/bxml/AttributeNode.java         |  52 ++
 .../processors/evtx/parser/bxml/BxmlNode.java   | 134 ++++++
 .../evtx/parser/bxml/BxmlNodeFactory.java       |  27 ++
 .../evtx/parser/bxml/BxmlNodeWithToken.java     |  43 ++
 .../parser/bxml/BxmlNodeWithTokenAndString.java |  65 +++
 .../evtx/parser/bxml/CDataSectionNode.java      |  61 +++
 .../evtx/parser/bxml/CloseElementNode.java      |  49 ++
 .../evtx/parser/bxml/CloseEmptyElementNode.java |  46 ++
 .../evtx/parser/bxml/CloseStartElementNode.java |  49 ++
 .../bxml/ConditionalSubstitutionNode.java       |  61 +++
 .../evtx/parser/bxml/EndOfStreamNode.java       |  46 ++
 .../evtx/parser/bxml/EntityReferenceNode.java   |  50 ++
 .../evtx/parser/bxml/NameStringNode.java        |  69 +++
 .../parser/bxml/NormalSubstitutionNode.java     |  61 +++
 .../evtx/parser/bxml/OpenStartElementNode.java  |  81 ++++
 .../bxml/ProcessingInstructionDataNode.java     |  58 +++
 .../bxml/ProcessingInstructionTargetNode.java   |  47 ++
 .../processors/evtx/parser/bxml/RootNode.java   |  83 ++++
 .../evtx/parser/bxml/StreamStartNode.java       |  58 +++
 .../evtx/parser/bxml/TemplateInstanceNode.java  |  87 ++++
 .../evtx/parser/bxml/TemplateNode.java          |  78 +++
 .../processors/evtx/parser/bxml/ValueNode.java  | 111 +++++
 .../evtx/parser/bxml/value/BXmlTypeNode.java    |  46 ++
 .../evtx/parser/bxml/value/BinaryTypeNode.java  |  46 ++
 .../evtx/parser/bxml/value/BooleanTypeNode.java |  43 ++
 .../evtx/parser/bxml/value/DoubleTypeNode.java  |  43 ++
 .../parser/bxml/value/FiletimeTypeNode.java     |  49 ++
 .../evtx/parser/bxml/value/FloatTypeNode.java   |  43 ++
 .../evtx/parser/bxml/value/GuidTypeNode.java    |  41 ++
 .../evtx/parser/bxml/value/Hex32TypeNode.java   |  41 ++
 .../evtx/parser/bxml/value/Hex64TypeNode.java   |  41 ++
 .../evtx/parser/bxml/value/NullTypeNode.java    |  38 ++
 .../evtx/parser/bxml/value/SIDTypeNode.java     |  54 +++
 .../parser/bxml/value/SignedByteTypeNode.java   |  41 ++
 .../parser/bxml/value/SignedDWordTypeNode.java  |  42 ++
 .../parser/bxml/value/SignedQWordTypeNode.java  |  42 ++
 .../parser/bxml/value/SignedWordTypeNode.java   |  41 ++
 .../evtx/parser/bxml/value/SizeTypeNode.java    |  45 ++
 .../evtx/parser/bxml/value/StringTypeNode.java  |  45 ++
 .../parser/bxml/value/SystemtimeTypeNode.java   |  61 +++
 .../parser/bxml/value/UnsignedByteTypeNode.java |  41 ++
 .../bxml/value/UnsignedDWordTypeNode.java       |  42 ++
 .../bxml/value/UnsignedQWordTypeNode.java       |  42 ++
 .../parser/bxml/value/UnsignedWordTypeNode.java |  41 ++
 .../evtx/parser/bxml/value/VariantTypeNode.java |  52 ++
 .../bxml/value/VariantTypeNodeFactory.java      |  28 ++
 .../parser/bxml/value/WStringArrayTypeNode.java |  68 +++
 .../evtx/parser/bxml/value/WStringTypeNode.java |  46 ++
 .../org.apache.nifi.processor.Processor         |  17 +
 .../additionalDetails.html                      |  91 ++++
 .../evtx/MalformedChunkHandlerTest.java         |  77 +++
 .../nifi/processors/evtx/ParseEvtxTest.java     | 481 +++++++++++++++++++
 .../processors/evtx/ResultProcessorTest.java    |  86 ++++
 .../processors/evtx/XmlBxmlNodeVisitorTest.java | 325 +++++++++++++
 .../processors/evtx/XmlRootNodeHandlerTest.java |  74 +++
 .../evtx/parser/BinaryReaderTest.java           | 208 ++++++++
 .../processors/evtx/parser/ChunkHeaderTest.java | 145 ++++++
 .../processors/evtx/parser/FileHeaderTest.java  |  85 ++++
 .../nifi/processors/evtx/parser/RecordTest.java |  73 +++
 .../evtx/parser/TestBinaryReaderBuilder.java    | 168 +++++++
 .../evtx/parser/bxml/AttributeNodeTest.java     |  74 +++
 .../evtx/parser/bxml/BxmlNodeTestBase.java      |  43 ++
 .../BxmlNodeWithTokenAndStringTestBase.java     |  34 ++
 .../parser/bxml/BxmlNodeWithTokenTestBase.java  |  30 ++
 .../evtx/parser/bxml/CDataSectionNodeTest.java  |  60 +++
 .../evtx/parser/bxml/CloseElementNodeTest.java  |  50 ++
 .../parser/bxml/CloseEmptyElementNodeTest.java  |  56 +++
 .../parser/bxml/CloseStartElementNodeTest.java  |  56 +++
 .../bxml/ConditionalSubstitutionNodeTest.java   |  63 +++
 .../evtx/parser/bxml/EndOfStreamNodeTest.java   |  56 +++
 .../parser/bxml/EntityReferenceNodeTest.java    |  67 +++
 .../evtx/parser/bxml/NameStringNodeTest.java    |  67 +++
 .../parser/bxml/NormalSubstitutionNodeTest.java |  61 +++
 .../parser/bxml/OpenStartElementNodeTest.java   | 105 ++++
 .../bxml/ProcessingInstructionDataNodeTest.java |  70 +++
 .../ProcessingInstructionTargetNodeTest.java    |  63 +++
 .../evtx/parser/bxml/RootNodeTest.java          |  70 +++
 .../evtx/parser/bxml/StreamStartNodeTest.java   |  59 +++
 .../parser/bxml/TemplateInstanceNodeTest.java   |  99 ++++
 .../evtx/parser/bxml/TemplateNodeTest.java      |  71 +++
 .../evtx/parser/bxml/ValueNodeTest.java         |  63 +++
 .../parser/bxml/value/BXmlTypeNodeTest.java     |  52 ++
 .../parser/bxml/value/BinaryTypeNodeTest.java   |  52 ++
 .../parser/bxml/value/BooleanTypeNodeTest.java  |  38 ++
 .../parser/bxml/value/DoubleTypeNodeTest.java   |  33 ++
 .../parser/bxml/value/FiletimeTypeNodeTest.java |  35 ++
 .../parser/bxml/value/FloatTypeNodeTest.java    |  34 ++
 .../parser/bxml/value/GuidTypeNodeTest.java     |  33 ++
 .../parser/bxml/value/Hex32TypeNodeTest.java    |  35 ++
 .../parser/bxml/value/Hex64TypeNodeTest.java    |  35 ++
 .../parser/bxml/value/NullTypeNodeTest.java     |  32 ++
 .../evtx/parser/bxml/value/SIDTypeNodeTest.java |  37 ++
 .../bxml/value/SignedByteTypeNodeTest.java      |  33 ++
 .../bxml/value/SignedDWordTypeNodeTest.java     |  34 ++
 .../bxml/value/SignedQWordTypeNodeTest.java     |  34 ++
 .../bxml/value/SignedWordTypeNodeTest.java      |  34 ++
 .../parser/bxml/value/SizeTypeNodeTest.java     |  43 ++
 .../parser/bxml/value/StringTypeNodeTest.java   |  41 ++
 .../bxml/value/SystemtimeTypeNodeTest.java      |  35 ++
 .../bxml/value/UnsignedByteTypeNodeTest.java    |  34 ++
 .../bxml/value/UnsignedDWordTypeNodeTest.java   |  35 ++
 .../bxml/value/UnsignedQWordTypeNodeTest.java   |  35 ++
 .../bxml/value/UnsignedWordTypeNodeTest.java    |  34 ++
 .../bxml/value/WStringArrayTypeNodeTest.java    |  53 ++
 .../parser/bxml/value/WStringTypeNodeTest.java  |  39 ++
 .../src/test/resources/application-logs.evtx    | Bin 0 -> 1118209 bytes
 nifi-nar-bundles/nifi-evtx-bundle/pom.xml       |  51 ++
 nifi-nar-bundles/pom.xml                        |   1 +
 pom.xml                                         |   6 +
 133 files changed, 8862 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/NOTICE
----------------------------------------------------------------------
diff --git a/NOTICE b/NOTICE
index 6ec9ef9..9661690 100644
--- a/NOTICE
+++ b/NOTICE
@@ -7,3 +7,8 @@ The Apache Software Foundation (http://www.apache.org/).
 This product includes the following work from the Apache Hadoop project:
 
 BoundedByteArrayOutputStream.java adapted to 
SoftLimitBoundedByteArrayOutputStream.java
+
+This includes derived works from the Apache Software License V2 library 
python-evtx (https://github.com/williballenthin/python-evtx)
+Copyright 2012, 2013 Willi Ballenthin [email protected]
+while at Mandiant http://www.mandiant.com
+The derived work is adapted from Evtx/Evtx.py, Evtx/BinaryParser.py, 
Evtx/Nodes.py, Evtx/Views.py and can be found in the 
org.apache.nifi.processors.evtx.parser package.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-assembly/NOTICE
----------------------------------------------------------------------
diff --git a/nifi-assembly/NOTICE b/nifi-assembly/NOTICE
index bfdb0bd..d3b9461 100644
--- a/nifi-assembly/NOTICE
+++ b/nifi-assembly/NOTICE
@@ -802,6 +802,12 @@ The following binary components are provided under the 
Apache Software License v
        The code for the t-digest was originally authored by Ted Dunning
        A number of small but very helpful changes have been contributed by 
Adrien Grand (https://github.com/jpountz)
 
+
+This includes derived works from the Apache Software License V2 library 
python-evtx (https://github.com/williballenthin/python-evtx)
+Copyright 2012, 2013 Willi Ballenthin [email protected]
+while at Mandiant http://www.mandiant.com
+The derived work is adapted from Evtx/Evtx.py, Evtx/BinaryParser.py, 
Evtx/Nodes.py, Evtx/Views.py and can be found in the 
org.apache.nifi.processors.evtx.parser package.
+
 ************************
 Common Development and Distribution License 1.1
 ************************

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-assembly/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-assembly/pom.xml b/nifi-assembly/pom.xml
index 7f097cb..f655659 100644
--- a/nifi-assembly/pom.xml
+++ b/nifi-assembly/pom.xml
@@ -332,6 +332,11 @@ language governing permissions and limitations under the 
License. -->
             <artifactId>nifi-mqtt-nar</artifactId>
             <type>nar</type>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-evtx-nar</artifactId>
+            <type>nar</type>
+        </dependency>
     </dependencies>
 
     <properties>

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/pom.xml 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/pom.xml
new file mode 100644
index 0000000..40d5bff
--- /dev/null
+++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>nifi-evtx-bundle</artifactId>
+        <groupId>org.apache.nifi</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.nifi</groupId>
+    <artifactId>nifi-evtx-nar</artifactId>
+    <packaging>nar</packaging>
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <source.skip>true</source.skip>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-standard-services-api-nar</artifactId>
+            <type>nar</type>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-evtx-processors</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/src/main/resources/META-INF/LICENSE
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/src/main/resources/META-INF/LICENSE
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/src/main/resources/META-INF/LICENSE
new file mode 100644
index 0000000..f3c8ece
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/src/main/resources/META-INF/LICENSE
@@ -0,0 +1,209 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+APACHE NIFI SUBCOMPONENTS:
+
+The Apache NiFi project contains subcomponents with separate copyright
+notices and license terms. Your use of the source code for the these
+subcomponents is subject to the terms and conditions of the following
+licenses.

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/src/main/resources/META-INF/NOTICE
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/src/main/resources/META-INF/NOTICE
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/src/main/resources/META-INF/NOTICE
new file mode 100644
index 0000000..046197d
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-nar/src/main/resources/META-INF/NOTICE
@@ -0,0 +1,36 @@
+nifi-evtx-nar
+Copyright 2016 The Apache Software Foundation
+
+This includes derived works from the Apache Software License V2 library 
python-evtx (https://github.com/williballenthin/python-evtx)
+Copyright 2012, 2013 Willi Ballenthin [email protected]
+while at Mandiant http://www.mandiant.com
+The derived work is adapted from Evtx/Evtx.py, Evtx/BinaryParser.py, 
Evtx/Nodes.py, Evtx/Views.py and can be found in the 
org.apache.nifi.processors.evtx.parser package.
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+******************
+Apache Software License v2
+******************
+
+The following binary components are provided under the Apache Software License 
v2
+
+  (ASLv2) Apache Commons IO
+    The following NOTICE information applies:
+      Apache Commons IO
+      Copyright 2002-2012 The Apache Software Foundation
+
+  (ASLv2) Apache Commons Lang
+      The following NOTICE information applies:
+        Apache Commons Lang
+        Copyright 2001-2015 The Apache Software Foundation
+
+        This product includes software from the Spring Framework,
+        under the Apache License 2.0 (see: StringUtils.containsWhitespace())
+
+  (ASLv2) Guava
+    The following NOTICE information applies:
+      Guava
+      Copyright 2015 The Guava Authors
+
+

http://git-wip-us.apache.org/repos/asf/nifi/blob/a5fecda5/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/pom.xml 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/pom.xml
new file mode 100644
index 0000000..0c582de
--- /dev/null
+++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/pom.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>nifi-evtx-bundle</artifactId>
+        <groupId>org.apache.nifi</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>nifi-evtx-processors</artifactId>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-properties</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-processor-utils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-ssl-context-service-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-mock</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>

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/MalformedChunkHandler.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/MalformedChunkHandler.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/MalformedChunkHandler.java
new file mode 100644
index 0000000..4863d27
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/MalformedChunkHandler.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;
+
+import com.google.common.net.MediaType;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.flowfile.attributes.CoreAttributes;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.Relationship;
+
+/**
+ * Creates a FlowFile for the malformed chunk and transfers it to the 
badChunkRelationship
+ */
+public class MalformedChunkHandler {
+    private final Relationship badChunkRelationship;
+
+    public MalformedChunkHandler(Relationship badChunkRelationship) {
+        this.badChunkRelationship = badChunkRelationship;
+    }
+
+    public void handle(FlowFile original, ProcessSession processSession, 
String chunkName, byte[] badChunk) {
+        FlowFile flowFile = processSession.create(original);
+        flowFile = processSession.putAttribute(flowFile, 
CoreAttributes.FILENAME.key(), chunkName);
+        flowFile = processSession.putAttribute(flowFile, 
CoreAttributes.MIME_TYPE.key(), MediaType.APPLICATION_BINARY.toString());
+        flowFile = processSession.write(flowFile, out -> out.write(badChunk));
+        processSession.transfer(flowFile, badChunkRelationship);
+    }
+}

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/ParseEvtx.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/ParseEvtx.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/ParseEvtx.java
new file mode 100644
index 0000000..b0b6116
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/ParseEvtx.java
@@ -0,0 +1,290 @@
+/*
+ * 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;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.nifi.annotation.behavior.EventDriven;
+import org.apache.nifi.annotation.behavior.InputRequirement;
+import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
+import org.apache.nifi.annotation.behavior.ReadsAttribute;
+import org.apache.nifi.annotation.behavior.ReadsAttributes;
+import org.apache.nifi.annotation.behavior.SideEffectFree;
+import org.apache.nifi.annotation.behavior.SupportsBatching;
+import org.apache.nifi.annotation.behavior.WritesAttribute;
+import org.apache.nifi.annotation.behavior.WritesAttributes;
+import org.apache.nifi.annotation.documentation.CapabilityDescription;
+import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.flowfile.attributes.CoreAttributes;
+import org.apache.nifi.logging.ComponentLog;
+import org.apache.nifi.processor.AbstractProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processors.evtx.parser.ChunkHeader;
+import org.apache.nifi.processors.evtx.parser.FileHeader;
+import org.apache.nifi.processors.evtx.parser.FileHeaderFactory;
+import org.apache.nifi.processors.evtx.parser.MalformedChunkException;
+import org.apache.nifi.processors.evtx.parser.Record;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+@SideEffectFree
+@EventDriven
+@SupportsBatching
+@InputRequirement(Requirement.INPUT_REQUIRED)
+@Tags({"logs", "windows", "event", "evtx", "message", "file"})
+@CapabilityDescription("Parses the contents of a Windows Event Log file (evtx) 
and writes the resulting XML to the FlowFile")
+@ReadsAttributes({
+        @ReadsAttribute(attribute = "filename", description = "The filename of 
the evtx file")
+})
+@WritesAttributes({
+        @WritesAttribute(attribute = "filename", description = "The output 
filename"),
+        @WritesAttribute(attribute = "mime.type", description = "The output 
filetype (application/xml for success and failure relationships, original value 
for bad chunk and original relationships)"),
+})
+public class ParseEvtx extends AbstractProcessor {
+    public static final String RECORD = "Record";
+    public static final String CHUNK = "Chunk";
+    public static final String FILE = "File";
+    public static final String EVTX_EXTENSION = ".evtx";
+    public static final String XML_EXTENSION = ".xml";
+
+    @VisibleForTesting
+    static final Relationship REL_SUCCESS = new Relationship.Builder()
+            .name("success")
+            .description("Any FlowFile that was successfully converted from 
evtx to XML")
+            .build();
+
+    @VisibleForTesting
+    static final Relationship REL_FAILURE = new Relationship.Builder()
+            .name("failure")
+            .description("Any FlowFile that encountered an exception during 
conversion will be transferred to this relationship with as much parsing as 
possible done")
+            .build();
+
+    @VisibleForTesting
+    static final Relationship REL_BAD_CHUNK = new Relationship.Builder()
+            .name("bad chunk")
+            .description("Any bad chunks of records will be transferred to 
this relationship in their original binary form")
+            .build();
+
+    @VisibleForTesting
+    static final Relationship REL_ORIGINAL = new Relationship.Builder()
+            .name("original")
+            .description("The unmodified input FlowFile will be transferred to 
this relationship")
+            .build();
+
+    @VisibleForTesting
+    static final Set<Relationship> RELATIONSHIPS = 
Collections.unmodifiableSet(new HashSet<>(Arrays.asList(REL_SUCCESS, 
REL_FAILURE, REL_ORIGINAL, REL_BAD_CHUNK)));
+
+    @VisibleForTesting
+    static final PropertyDescriptor GRANULARITY = new 
PropertyDescriptor.Builder()
+            .required(true)
+            .name("granularity")
+            .displayName("Granularity")
+            .description("Output flow file for each Record, Chunk, or File 
encountered in the event log")
+            .defaultValue(CHUNK)
+            .allowableValues(RECORD, CHUNK, FILE)
+            .build();
+
+    @VisibleForTesting
+    static final List<PropertyDescriptor> PROPERTY_DESCRIPTORS = 
Collections.unmodifiableList(Arrays.asList(GRANULARITY));
+
+    private final FileHeaderFactory fileHeaderFactory;
+    private final MalformedChunkHandler malformedChunkHandler;
+    private final RootNodeHandlerFactory rootNodeHandlerFactory;
+    private final ResultProcessor resultProcessor;
+
+    public ParseEvtx() {
+        this(FileHeader::new, new MalformedChunkHandler(REL_BAD_CHUNK), 
XmlRootNodeHandler::new, new ResultProcessor(REL_SUCCESS, REL_FAILURE));
+    }
+
+    public ParseEvtx(FileHeaderFactory fileHeaderFactory, 
MalformedChunkHandler malformedChunkHandler, RootNodeHandlerFactory 
rootNodeHandlerFactory, ResultProcessor resultProcessor) {
+        this.fileHeaderFactory = fileHeaderFactory;
+        this.malformedChunkHandler = malformedChunkHandler;
+        this.rootNodeHandlerFactory = rootNodeHandlerFactory;
+        this.resultProcessor = resultProcessor;
+    }
+
+    protected String getName(String basename, Object chunkNumber, Object 
recordNumber, String extension) {
+        StringBuilder stringBuilder = new StringBuilder(basename);
+        if (chunkNumber != null) {
+            stringBuilder.append("-chunk");
+            stringBuilder.append(chunkNumber);
+        }
+        if (recordNumber != null) {
+            stringBuilder.append("-record");
+            stringBuilder.append(recordNumber);
+        }
+        stringBuilder.append(extension);
+        return stringBuilder.toString();
+    }
+
+    protected String getBasename(FlowFile flowFile, ComponentLog logger) {
+        String basename = flowFile.getAttribute(CoreAttributes.FILENAME.key());
+        if (basename.endsWith(EVTX_EXTENSION)) {
+            return basename.substring(0, basename.length() - 
EVTX_EXTENSION.length());
+        } else {
+            logger.warn("Trying to parse file without .evtx extension {} from 
flowfile {}", new Object[]{basename, flowFile});
+            return basename;
+        }
+    }
+
+    @Override
+    public void onTrigger(ProcessContext context, ProcessSession session) 
throws ProcessException {
+        ComponentLog logger = getLogger();
+        final FlowFile flowFile = session.get();
+        if (flowFile == null) {
+            return;
+        }
+        String basename = getBasename(flowFile, logger);
+        String granularity = context.getProperty(GRANULARITY).getValue();
+        if (FILE.equals(granularity)) {
+            // File granularity will emit a FlowFile for each input
+            FlowFile original = session.clone(flowFile);
+            AtomicReference<Exception> exceptionReference = new 
AtomicReference<>(null);
+            FlowFile updated = session.write(flowFile, (in, out) -> {
+                processFileGranularity(session, logger, original, basename, 
exceptionReference, in, out);
+            });
+            session.transfer(original, REL_ORIGINAL);
+            resultProcessor.process(session, logger, updated, 
exceptionReference.get(), getName(basename, null, null, XML_EXTENSION));
+        } else {
+            session.read(flowFile, in -> {
+                if (RECORD.equals(granularity)) {
+                    // Record granularity will emit a FlowFile for every 
record (event)
+                    processRecordGranularity(session, logger, flowFile, 
basename, in);
+                } else if (CHUNK.equals(granularity)) {
+                    // Chunk granularity will emit a FlowFile for each chunk 
of the file
+                    processChunkGranularity(session, logger, flowFile, 
basename, in);
+                }
+            });
+            session.transfer(flowFile, REL_ORIGINAL);
+        }
+    }
+
+    protected void processFileGranularity(ProcessSession session, ComponentLog 
componentLog, FlowFile original, String basename,
+                                          AtomicReference<Exception> 
exceptionReference, InputStream in, OutputStream out) throws IOException {
+        FileHeader fileHeader = fileHeaderFactory.create(in, componentLog);
+        try (RootNodeHandler rootNodeHandler = 
rootNodeHandlerFactory.create(out)) {
+            while (fileHeader.hasNext()) {
+                try {
+                    ChunkHeader chunkHeader = fileHeader.next();
+                    try {
+                        while (chunkHeader.hasNext()) {
+                            
rootNodeHandler.handle(chunkHeader.next().getRootNode());
+                        }
+                    } catch (IOException e) {
+                        malformedChunkHandler.handle(original, session, 
getName(basename, chunkHeader.getChunkNumber(), null, EVTX_EXTENSION), 
chunkHeader.getBinaryReader().getBytes());
+                        exceptionReference.set(e);
+                    }
+                } catch (MalformedChunkException e) {
+                    malformedChunkHandler.handle(original, session, 
getName(basename, e.getChunkNum(), null, EVTX_EXTENSION), e.getBadChunk());
+                }
+            }
+        } catch (IOException e) {
+            exceptionReference.set(e);
+        }
+    }
+
+    protected void processChunkGranularity(ProcessSession session, 
ComponentLog componentLog, FlowFile flowFile, String basename, InputStream in) 
throws IOException {
+        FileHeader fileHeader = fileHeaderFactory.create(in, componentLog);
+        while (fileHeader.hasNext()) {
+            try {
+                ChunkHeader chunkHeader = fileHeader.next();
+                FlowFile updated = session.create(flowFile);
+                AtomicReference<Exception> exceptionReference = new 
AtomicReference<>(null);
+                updated = session.write(updated, out -> {
+                    try (RootNodeHandler rootNodeHandler = 
rootNodeHandlerFactory.create(out)) {
+                        while (chunkHeader.hasNext()) {
+                            try {
+                                
rootNodeHandler.handle(chunkHeader.next().getRootNode());
+                            } catch (IOException e) {
+                                exceptionReference.set(e);
+                                break;
+                            }
+                        }
+                    } catch (IOException e) {
+                        exceptionReference.set(e);
+                    }
+                });
+                Exception exception = exceptionReference.get();
+                resultProcessor.process(session, componentLog, updated, 
exception, getName(basename, chunkHeader.getChunkNumber(), null, 
XML_EXTENSION));
+                if (exception != null) {
+                    malformedChunkHandler.handle(flowFile, session, 
getName(basename, chunkHeader.getChunkNumber(), null, EVTX_EXTENSION), 
chunkHeader.getBinaryReader().getBytes());
+                }
+            } catch (MalformedChunkException e) {
+                malformedChunkHandler.handle(flowFile, session, 
getName(basename, e.getChunkNum(), null, EVTX_EXTENSION), e.getBadChunk());
+            }
+        }
+    }
+
+    protected void processRecordGranularity(ProcessSession session, 
ComponentLog componentLog, FlowFile flowFile, String basename, InputStream in) 
throws IOException {
+        FileHeader fileHeader = fileHeaderFactory.create(in, componentLog);
+        while (fileHeader.hasNext()) {
+            try {
+                ChunkHeader chunkHeader = fileHeader.next();
+                while (chunkHeader.hasNext()) {
+                    FlowFile updated = session.create(flowFile);
+                    AtomicReference<Exception> exceptionReference = new 
AtomicReference<>(null);
+                    try {
+                        Record record = chunkHeader.next();
+                        updated = session.write(updated, out -> {
+                            try (RootNodeHandler rootNodeHandler = 
rootNodeHandlerFactory.create(out)) {
+                                try {
+                                    
rootNodeHandler.handle(record.getRootNode());
+                                } catch (IOException e) {
+                                    exceptionReference.set(e);
+                                }
+                            } catch (IOException e) {
+                                exceptionReference.set(e);
+                            }
+                        });
+                        resultProcessor.process(session, componentLog, 
updated, exceptionReference.get(), getName(basename, 
chunkHeader.getChunkNumber(), record.getRecordNum(), XML_EXTENSION));
+                    } catch (Exception e) {
+                        exceptionReference.set(e);
+                        session.remove(updated);
+                    }
+                    if (exceptionReference.get() != null) {
+                        malformedChunkHandler.handle(flowFile, session, 
getName(basename, chunkHeader.getChunkNumber(), null, EVTX_EXTENSION), 
chunkHeader.getBinaryReader().getBytes());
+                    }
+                }
+            } catch (MalformedChunkException e) {
+                malformedChunkHandler.handle(flowFile, session, 
getName(basename, e.getChunkNum(), null, EVTX_EXTENSION), e.getBadChunk());
+            }
+        }
+    }
+
+    @Override
+    public Set<Relationship> getRelationships() {
+        return RELATIONSHIPS;
+    }
+
+    @Override
+    protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
+        return PROPERTY_DESCRIPTORS;
+    }
+}

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/ResultProcessor.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/ResultProcessor.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/ResultProcessor.java
new file mode 100644
index 0000000..bcb667c
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/ResultProcessor.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;
+
+import com.google.common.net.MediaType;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.flowfile.attributes.CoreAttributes;
+import org.apache.nifi.logging.ComponentLog;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.Relationship;
+
+public class ResultProcessor {
+    private final Relationship successRelationship;
+    private final Relationship failureRelationship;
+    public static final String UNABLE_TO_PROCESS_DUE_TO = "Unable to process 
{} due to {}";
+
+    public ResultProcessor(Relationship successRelationship, Relationship 
failureRelationship) {
+        this.successRelationship = successRelationship;
+        this.failureRelationship = failureRelationship;
+    }
+
+    public void process(ProcessSession session, ComponentLog logger, FlowFile 
updated, Exception exception, String name) {
+        updated = session.putAttribute(updated, CoreAttributes.FILENAME.key(), 
name);
+        updated = session.putAttribute(updated, 
CoreAttributes.MIME_TYPE.key(), MediaType.APPLICATION_XML_UTF_8.toString());
+        if (exception == null) {
+            session.transfer(updated, successRelationship);
+        } else {
+            logger.error(UNABLE_TO_PROCESS_DUE_TO, new Object[]{name, 
exception}, exception);
+            session.transfer(updated, failureRelationship);
+        }
+    }
+}

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/RootNodeHandler.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/RootNodeHandler.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/RootNodeHandler.java
new file mode 100644
index 0000000..cfceea2
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/RootNodeHandler.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;
+
+import org.apache.nifi.processors.evtx.parser.bxml.RootNode;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+public interface RootNodeHandler extends Closeable {
+    void handle(RootNode rootNode) 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/RootNodeHandlerFactory.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/RootNodeHandlerFactory.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/RootNodeHandlerFactory.java
new file mode 100644
index 0000000..7e98a8c
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/RootNodeHandlerFactory.java
@@ -0,0 +1,25 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public interface RootNodeHandlerFactory {
+    RootNodeHandler create(OutputStream outputStream) 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/XmlBxmlNodeVisitor.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/XmlBxmlNodeVisitor.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/XmlBxmlNodeVisitor.java
new file mode 100644
index 0000000..9a3ffa0
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/XmlBxmlNodeVisitor.java
@@ -0,0 +1,190 @@
+/*
+ * 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;
+
+import org.apache.nifi.processors.evtx.parser.BxmlNodeVisitor;
+import org.apache.nifi.processors.evtx.parser.bxml.AttributeNode;
+import org.apache.nifi.processors.evtx.parser.bxml.BxmlNode;
+import org.apache.nifi.processors.evtx.parser.bxml.CDataSectionNode;
+import org.apache.nifi.processors.evtx.parser.bxml.ConditionalSubstitutionNode;
+import org.apache.nifi.processors.evtx.parser.bxml.EntityReferenceNode;
+import org.apache.nifi.processors.evtx.parser.bxml.NormalSubstitutionNode;
+import org.apache.nifi.processors.evtx.parser.bxml.OpenStartElementNode;
+import org.apache.nifi.processors.evtx.parser.bxml.RootNode;
+import org.apache.nifi.processors.evtx.parser.bxml.TemplateInstanceNode;
+import org.apache.nifi.processors.evtx.parser.bxml.TemplateNode;
+import org.apache.nifi.processors.evtx.parser.bxml.ValueNode;
+import org.apache.nifi.processors.evtx.parser.bxml.value.BXmlTypeNode;
+import org.apache.nifi.processors.evtx.parser.bxml.value.VariantTypeNode;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Visitor that writes an event to the XMLStreamWriter
+ */
+public class XmlBxmlNodeVisitor implements BxmlNodeVisitor {
+    private final XMLStreamWriter xmlStreamWriter;
+    private List<VariantTypeNode> substitutions;
+
+    public XmlBxmlNodeVisitor(XMLStreamWriter xmlStreamWriter, RootNode 
rootNode) throws IOException {
+        this.xmlStreamWriter = xmlStreamWriter;
+        substitutions = rootNode.getSubstitutions();
+        for (BxmlNode bxmlNode : rootNode.getChildren()) {
+            bxmlNode.accept(this);
+        }
+    }
+
+    @Override
+    public void visit(OpenStartElementNode openStartElementNode) throws 
IOException {
+        try {
+            
xmlStreamWriter.writeStartElement(openStartElementNode.getTagName());
+            try {
+                List<BxmlNode> nonAttributeChildren = new ArrayList<>();
+                for (BxmlNode bxmlNode : openStartElementNode.getChildren()) {
+                    if (bxmlNode instanceof AttributeNode) {
+                        bxmlNode.accept(this);
+                    } else {
+                        nonAttributeChildren.add(bxmlNode);
+                    }
+                }
+                for (BxmlNode nonAttributeChild : nonAttributeChildren) {
+                    nonAttributeChild.accept(this);
+                }
+            } finally {
+                xmlStreamWriter.writeEndElement();
+            }
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public void visit(AttributeNode attributeNode) throws IOException {
+        try {
+            AttributeNodeVisitor attributeNodeVisitor = new 
AttributeNodeVisitor();
+            attributeNodeVisitor.visit(attributeNode);
+            xmlStreamWriter.writeAttribute(attributeNode.getAttributeName(), 
attributeNodeVisitor.getValue());
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public void visit(TemplateInstanceNode templateInstanceNode) throws 
IOException {
+        templateInstanceNode.getTemplateNode().accept(this);
+    }
+
+    @Override
+    public void visit(TemplateNode templateNode) throws IOException {
+        for (BxmlNode bxmlNode : templateNode.getChildren()) {
+            bxmlNode.accept(this);
+        }
+    }
+
+    @Override
+    public void visit(RootNode rootNode) throws IOException {
+        new XmlBxmlNodeVisitor(xmlStreamWriter, rootNode);
+    }
+
+    @Override
+    public void visit(CDataSectionNode cDataSectionNode) throws IOException {
+        try {
+            xmlStreamWriter.writeCData(cDataSectionNode.getCdata());
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public void visit(EntityReferenceNode entityReferenceNode) throws 
IOException {
+        try {
+            xmlStreamWriter.writeCharacters(entityReferenceNode.getValue());
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public void visit(ValueNode valueNode) throws IOException {
+        for (BxmlNode bxmlNode : valueNode.getChildren()) {
+            bxmlNode.accept(this);
+        }
+    }
+
+    @Override
+    public void visit(ConditionalSubstitutionNode conditionalSubstitutionNode) 
throws IOException {
+        substitutions.get(conditionalSubstitutionNode.getIndex()).accept(this);
+    }
+
+    @Override
+    public void visit(NormalSubstitutionNode normalSubstitutionNode) throws 
IOException {
+        substitutions.get(normalSubstitutionNode.getIndex()).accept(this);
+    }
+
+    @Override
+    public void visit(VariantTypeNode variantTypeNode) throws IOException {
+        try {
+            if (variantTypeNode instanceof BXmlTypeNode) {
+                ((BXmlTypeNode) variantTypeNode).getRootNode().accept(this);
+            } else {
+                xmlStreamWriter.writeCharacters(variantTypeNode.getValue());
+            }
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+
+    private class AttributeNodeVisitor implements BxmlNodeVisitor {
+        private String value;
+
+        public String getValue() {
+            return value;
+        }
+
+        @Override
+        public void visit(AttributeNode attributeNode) throws IOException {
+            attributeNode.getValue().accept(this);
+        }
+
+        @Override
+        public void visit(ValueNode valueNode) throws IOException {
+            for (BxmlNode bxmlNode : valueNode.getChildren()) {
+                bxmlNode.accept(this);
+            }
+        }
+
+        @Override
+        public void visit(VariantTypeNode variantTypeNode) throws IOException {
+            value = variantTypeNode.getValue();
+        }
+
+        @Override
+        public void visit(NormalSubstitutionNode normalSubstitutionNode) 
throws IOException {
+            value = 
substitutions.get(normalSubstitutionNode.getIndex()).getValue();
+        }
+
+        @Override
+        public void visit(ConditionalSubstitutionNode 
conditionalSubstitutionNode) throws IOException {
+            value = 
substitutions.get(conditionalSubstitutionNode.getIndex()).getValue();
+        }
+    }
+}

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/XmlBxmlNodeVisitorFactory.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/XmlBxmlNodeVisitorFactory.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/XmlBxmlNodeVisitorFactory.java
new file mode 100644
index 0000000..5c4e571
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/XmlBxmlNodeVisitorFactory.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;
+
+import org.apache.nifi.processors.evtx.parser.bxml.RootNode;
+
+import javax.xml.stream.XMLStreamWriter;
+import java.io.IOException;
+
+public interface XmlBxmlNodeVisitorFactory {
+    XmlBxmlNodeVisitor create(XMLStreamWriter xmlStreamWriter, RootNode 
rootNode) 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/XmlRootNodeHandler.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/XmlRootNodeHandler.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/XmlRootNodeHandler.java
new file mode 100644
index 0000000..ad4ce39
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/XmlRootNodeHandler.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;
+
+import org.apache.nifi.processors.evtx.parser.bxml.RootNode;
+import org.apache.nifi.stream.io.BufferedOutputStream;
+
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class XmlRootNodeHandler implements RootNodeHandler {
+    public static final String EVENTS = "Events";
+    private static final XMLOutputFactory XML_OUTPUT_FACTORY = 
XMLOutputFactory.newFactory();
+
+    private final XMLStreamWriter xmlStreamWriter;
+    private final XmlBxmlNodeVisitorFactory xmlBxmlNodeVisitorFactory;
+
+    public XmlRootNodeHandler(OutputStream outputStream) throws IOException {
+        this(getXmlStreamWriter(new BufferedOutputStream(outputStream)), 
XmlBxmlNodeVisitor::new);
+    }
+
+    public XmlRootNodeHandler(XMLStreamWriter xmlStreamWriter, 
XmlBxmlNodeVisitorFactory xmlBxmlNodeVisitorFactory) throws IOException {
+        this.xmlStreamWriter = xmlStreamWriter;
+        this.xmlBxmlNodeVisitorFactory = xmlBxmlNodeVisitorFactory;
+        try {
+            this.xmlStreamWriter.writeStartDocument();
+            try {
+                this.xmlStreamWriter.writeStartElement(EVENTS);
+            } catch (XMLStreamException e) {
+                this.xmlStreamWriter.close();
+                throw e;
+            }
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+
+    private static XMLStreamWriter getXmlStreamWriter(OutputStream 
outputStream) throws IOException {
+        try {
+            return XML_OUTPUT_FACTORY.createXMLStreamWriter(outputStream, 
"UTF-8");
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+
+    @Override
+    public void handle(RootNode rootNode) throws IOException {
+        xmlBxmlNodeVisitorFactory.create(xmlStreamWriter, rootNode);
+    }
+
+    @Override
+    public void close() throws IOException {
+        try {
+            xmlStreamWriter.writeEndElement();
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        } finally {
+            try {
+                xmlStreamWriter.close();
+            } catch (XMLStreamException e) {
+                throw new IOException(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/BinaryReader.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/BinaryReader.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/BinaryReader.java
new file mode 100644
index 0000000..12f1f13
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/BinaryReader.java
@@ -0,0 +1,294 @@
+/*
+ * 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.commons.io.Charsets;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Date;
+
+/**
+ * Class to simplify reading binary values from the evtx file
+ */
+public class BinaryReader {
+    public static final long EPOCH_OFFSET = 11644473600000L;
+    public static final int[][] INDEX_ARRAYS = new int[][]{{3, 2, 1, 0}, {5, 
4}, {7, 6}, {8, 9}, {10, 11, 12, 13, 14, 15}};
+    private final byte[] bytes;
+    private int position;
+
+    /**
+     * Constructs a binary reader with the given one's byte array and an 
arbitrary position
+     *
+     * @param binaryReader the source BinaryReader
+     * @param position     the new position
+     */
+    public BinaryReader(BinaryReader binaryReader, int position) {
+        this.bytes = binaryReader.bytes;
+        this.position = position;
+    }
+
+    /**
+     * Reads size bytes from the inputStream and creates a BinaryReader for 
them
+     *
+     * @param inputStream the input stream
+     * @param size        the number of bytes
+     * @throws IOException if there is an error reading from the input stream
+     */
+    public BinaryReader(InputStream inputStream, int size) throws IOException {
+        byte[] bytes = new byte[size];
+        int read = 0;
+        while (read < size) {
+            read += inputStream.read(bytes, read, size - read);
+        }
+        this.bytes = bytes;
+        this.position = 0;
+    }
+
+    /**
+     * Creates a BinaryReader for the given bytes
+     *
+     * @param bytes the bytes
+     */
+    public BinaryReader(byte[] bytes) {
+        this.bytes = bytes;
+        this.position = 0;
+    }
+
+    /**
+     * Reads a single byte
+     *
+     * @return the byte's int value
+     */
+    public int read() {
+        return bytes[position++];
+    }
+
+    /**
+     * Returns the byte that would be read without changing the posiiton
+     *
+     * @return the byte that would be read without changing the posiiton
+     */
+    public int peek() {
+        return bytes[position];
+    }
+
+    /**
+     * Returns the next length bytes without changing the position
+     *
+     * @param length the number of bytes
+     * @return the bytes
+     */
+    public byte[] peekBytes(int length) {
+        return Arrays.copyOfRange(bytes, position, position + length);
+    }
+
+    /**
+     * Reads the next length bytes
+     *
+     * @param length the number of bytes
+     * @return the bytes
+     */
+    public byte[] readBytes(int length) {
+        byte[] result = peekBytes(length);
+        position += length;
+        return result;
+    }
+
+    /**
+     * Reads the next length bytes into the buf buffer at a given offset
+     *
+     * @param buf    the buffer
+     * @param offset the offset
+     * @param length the number of bytes
+     */
+    public void readBytes(byte[] buf, int offset, int length) {
+        System.arraycopy(bytes, position, buf, offset, length);
+        position += length;
+    }
+
+    /**
+     * Reads an Evtx formatted guid (16 bytes arranged into the grouping 
described by INDEX_ARRAYS)
+     *
+     * @return the guid
+     */
+    public String readGuid() {
+        StringBuilder result = new StringBuilder();
+        int maxIndex = 0;
+        for (int[] indexArray : INDEX_ARRAYS) {
+            for (int index : indexArray) {
+                maxIndex = Math.max(maxIndex, index);
+                result.append(String.format("%02X", bytes[position + 
index]).toLowerCase());
+            }
+            result.append("-");
+        }
+        result.setLength(result.length() - 1);
+        position += (maxIndex + 1);
+        return result.toString();
+    }
+
+    /**
+     * Reads a string made up of single byte characters
+     *
+     * @param length the length
+     * @return the string
+     * @throws IOException if the String wasn't null terminated
+     */
+    public String readString(int length) throws IOException {
+        StringBuilder result = new StringBuilder(length - 1);
+        boolean foundNull = false;
+        int exclusiveLastIndex = position + length;
+        for (int i = position; i < exclusiveLastIndex; i++) {
+            byte b = bytes[i];
+            if (b == 0) {
+                foundNull = true;
+                break;
+            }
+            result.append((char) b);
+        }
+        if (!foundNull) {
+            throw new IOException("Expected null terminated string");
+        }
+        position += length;
+        return result.toString();
+    }
+
+    /**
+     * Reads a string encoded with UTF_16LE of a given length
+     *
+     * @param length the number of characters
+     * @return the string
+     */
+    public String readWString(int length) {
+        int numBytes = length * 2;
+        String result = Charsets.UTF_16LE.decode(ByteBuffer.wrap(bytes, 
position, numBytes)).toString();
+        position += numBytes;
+        return result;
+    }
+
+    /**
+     * Reads 8 bytes in litte endian order and returns the UnsignedLong value
+     *
+     * @return the value
+     */
+    public UnsignedLong readQWord() {
+        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes, position, 8);
+        position += 8;
+        return 
UnsignedLong.fromLongBits(byteBuffer.order(ByteOrder.LITTLE_ENDIAN).getLong());
+    }
+
+    /**
+     * Reads 4 bytes in little endian order and returns the UnsignedInteger 
value
+     *
+     * @return the value
+     */
+    public UnsignedInteger readDWord() {
+        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes, position, 4);
+        position += 4;
+        return 
UnsignedInteger.fromIntBits(byteBuffer.order(ByteOrder.LITTLE_ENDIAN).getInt());
+    }
+
+    /**
+     * Reads 4 bytes in big endian order and returns the UnsignedInteger value
+     *
+     * @return the value
+     */
+    public UnsignedInteger readDWordBE() {
+        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes, position, 4);
+        position += 4;
+        return 
UnsignedInteger.fromIntBits(byteBuffer.order(ByteOrder.BIG_ENDIAN).getInt());
+    }
+
+    /**
+     * Reads 2 bytes in little endian order and returns the int value
+     *
+     * @return the value
+     */
+    public int readWord() {
+        byte[] bytes = new byte[4];
+        readBytes(bytes, 0, 2);
+        return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
+    }
+
+    /**
+     * Reads 2 bytes in big endian order and returns the int value
+     *
+     * @return the value
+     */
+    public int readWordBE() {
+        byte[] bytes = new byte[4];
+        readBytes(bytes, 2, 2);
+        return ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getInt();
+    }
+
+    /**
+     * Reads a timestamp that is the number of hundreds of nanoseconds since 
Jan 1 1601
+     * (see 
http://integriography.wordpress.com/2010/01/16/using-phython-to-parse-and-present-windows-64-bit-timestamps/)
+     *
+     * @return the date corresponding to the timestamp
+     */
+    public Date readFileTime() {
+        UnsignedLong hundredsOfNanosecondsSinceJan11601 = readQWord();
+        long millisecondsSinceJan11601 = 
hundredsOfNanosecondsSinceJan11601.dividedBy(UnsignedLong.valueOf(10000)).longValue();
+        long millisecondsSinceEpoch = millisecondsSinceJan11601 - EPOCH_OFFSET;
+        return new Date(millisecondsSinceEpoch);
+    }
+
+    /**
+     * Reads length bytes and Bas64 encodes them
+     *
+     * @param length the number of bytes
+     * @return a Base64 encoded string
+     */
+    public String readAndBase64EncodeBinary(int length) {
+        return Base64.getEncoder().encodeToString(readBytes(length));
+    }
+
+    /**
+     * Skips bytes in the BinaryReader
+     *
+     * @param bytes the number of bytes to skip
+     */
+    public void skip(int bytes) {
+        position += bytes;
+    }
+
+    /**
+     * Returns the current position of the BinaryReader
+     *
+     * @return the current position
+     */
+    public int getPosition() {
+        return position;
+    }
+
+    /**
+     * Returns the backing byte array
+     *
+     * @return the byte array
+     */
+    public byte[] getBytes() {
+        return bytes;
+    }
+}

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/Block.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/Block.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/Block.java
new file mode 100644
index 0000000..c42c8b4
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/Block.java
@@ -0,0 +1,84 @@
+/*
+ * 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 java.io.IOException;
+
+/**
+ * Parent class of all Blocks and BxmlNodes.  Tracks offset, initialPosition.  
Has common initialization logic.
+ */
+public abstract class Block {
+    private final long offset;
+    private final int initialPosition;
+    private BinaryReader binaryReader;
+    private boolean initialized = false;
+
+    public Block(BinaryReader binaryReader) {
+        this(binaryReader, binaryReader.getPosition());
+    }
+
+    public Block(BinaryReader binaryReader, long offset) {
+        this.binaryReader = binaryReader;
+        this.initialPosition = binaryReader.getPosition();
+        this.offset = offset;
+    }
+
+    public BinaryReader getBinaryReader() {
+        return binaryReader;
+    }
+
+    public long getOffset() {
+        return offset;
+    }
+
+    protected void init(boolean clearBinaryReader) throws IOException {
+        if (initialized) {
+            throw new IOException("Initialize should only be called once");
+        } else {
+            initialized = true;
+        }
+        int skipAmount = getHeaderLength() - (binaryReader.getPosition() - 
initialPosition);
+        if (skipAmount > 0) {
+            binaryReader.skip(skipAmount);
+        }
+
+        if (clearBinaryReader) {
+            clearBinaryReader();
+        }
+    }
+
+    protected void init() throws IOException {
+        init(true);
+    }
+
+    protected void clearBinaryReader() {
+        this.binaryReader = null;
+    }
+
+    protected int getHeaderLength() {
+        return 0;
+    }
+
+    public boolean isInitialized() {
+        return initialized;
+    }
+
+    public int getInitialPosition() {
+        return initialPosition;
+    }
+}

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/BxmlNodeVisitor.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/BxmlNodeVisitor.java
 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/BxmlNodeVisitor.java
new file mode 100644
index 0000000..9b58a3e
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/BxmlNodeVisitor.java
@@ -0,0 +1,121 @@
+/*
+ * 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.processors.evtx.parser.bxml.AttributeNode;
+import org.apache.nifi.processors.evtx.parser.bxml.CDataSectionNode;
+import org.apache.nifi.processors.evtx.parser.bxml.CloseElementNode;
+import org.apache.nifi.processors.evtx.parser.bxml.CloseEmptyElementNode;
+import org.apache.nifi.processors.evtx.parser.bxml.CloseStartElementNode;
+import org.apache.nifi.processors.evtx.parser.bxml.ConditionalSubstitutionNode;
+import org.apache.nifi.processors.evtx.parser.bxml.EndOfStreamNode;
+import org.apache.nifi.processors.evtx.parser.bxml.EntityReferenceNode;
+import org.apache.nifi.processors.evtx.parser.bxml.NameStringNode;
+import org.apache.nifi.processors.evtx.parser.bxml.NormalSubstitutionNode;
+import org.apache.nifi.processors.evtx.parser.bxml.OpenStartElementNode;
+import 
org.apache.nifi.processors.evtx.parser.bxml.ProcessingInstructionDataNode;
+import 
org.apache.nifi.processors.evtx.parser.bxml.ProcessingInstructionTargetNode;
+import org.apache.nifi.processors.evtx.parser.bxml.RootNode;
+import org.apache.nifi.processors.evtx.parser.bxml.StreamStartNode;
+import org.apache.nifi.processors.evtx.parser.bxml.TemplateInstanceNode;
+import org.apache.nifi.processors.evtx.parser.bxml.TemplateNode;
+import org.apache.nifi.processors.evtx.parser.bxml.ValueNode;
+import org.apache.nifi.processors.evtx.parser.bxml.value.VariantTypeNode;
+
+import java.io.IOException;
+
+/**
+ * Visitor interface for traversing a RootNode
+ */
+public interface BxmlNodeVisitor {
+    default void visit(RootNode rootNode) throws IOException {
+
+    }
+
+    default void visit(TemplateInstanceNode templateInstanceNode) throws 
IOException {
+
+    }
+
+    default void visit(TemplateNode templateNode) throws IOException {
+
+    }
+
+    default void visit(ValueNode valueNode) throws IOException {
+
+    }
+
+    default void visit(StreamStartNode streamStartNode) throws IOException {
+
+    }
+
+    default void visit(ProcessingInstructionTargetNode 
processingInstructionTargetNode) throws IOException {
+
+    }
+
+    default void visit(ProcessingInstructionDataNode 
processingInstructionDataNode) throws IOException {
+
+    }
+
+    default void visit(OpenStartElementNode openStartElementNode) throws 
IOException {
+
+    }
+
+    default void visit(NormalSubstitutionNode normalSubstitutionNode) throws 
IOException {
+
+    }
+
+    default void visit(NameStringNode nameStringNode) throws IOException {
+
+    }
+
+    default void visit(EntityReferenceNode entityReferenceNode) throws 
IOException {
+
+    }
+
+    default void visit(EndOfStreamNode endOfStreamNode) throws IOException {
+
+    }
+
+    default void visit(ConditionalSubstitutionNode 
conditionalSubstitutionNode) throws IOException {
+
+    }
+
+    default void visit(CloseStartElementNode closeStartElementNode) throws 
IOException {
+
+    }
+
+    default void visit(CloseEmptyElementNode closeEmptyElementNode) throws 
IOException {
+
+    }
+
+    default void visit(CloseElementNode closeElementNode) throws IOException {
+
+    }
+
+    default void visit(CDataSectionNode cDataSectionNode) throws IOException {
+
+    }
+
+    default void visit(AttributeNode attributeNode) throws IOException {
+
+    }
+
+    default void visit(VariantTypeNode variantTypeNode) throws IOException {
+
+    }
+}

Reply via email to