From 33257b5e39266df3ccc59b4c6b9d4f626d4312ff Mon Sep 17 00:00:00 2001
From: Shon Ferguson <shonferg@users.sourceforge.net>
Date: Wed, 20 Sep 2006 19:31:17 +0000
Subject: [PATCH] Changed WriteNifTree, and WriteFileGroup functions to take
 NifInfo structures instead of version and user_version arguments. Changed
 ReadNifList and ReadNifTree to optionally fill a passed in NifInfo structure
 with information from the header of the NIF file they read. Fixed some tabs
 that were done with spaces instead of actual tab characters. Updated from
 XML.

---
 include/gen/Header.h |   6 +-
 include/niflib.h     |  58 ++++++++---
 src/gen/Header.cpp   |  18 ++--
 src/gen/enums.cpp    |   1 -
 src/gen/obj_impl.cpp | 118 +++++++++++-----------
 src/niflib.cpp       | 226 ++++++++++++++++++++++++-------------------
 6 files changed, 240 insertions(+), 187 deletions(-)

diff --git a/include/gen/Header.h b/include/gen/Header.h
index bcd68a62..1aceda4b 100644
--- a/include/gen/Header.h
+++ b/include/gen/Header.h
@@ -56,16 +56,16 @@ struct NIFLIB_API Header {
 	/*!
 	 * Could be the name of the creator of the NIF file?
 	 */
-	ShortString creator_;
+	ShortString creator;
 	/*!
 	 * Unknown. Can be something like 'TriStrip Process Script'.
 	 */
-	ShortString exportType_;
+	ShortString exportInfo1;
 	/*!
 	 * Unknown. Possibly the selected option of the export script. Can be
 	 * something like 'Default Export Script'.
 	 */
-	ShortString exportScript_;
+	ShortString exportInfo2;
 	/*!
 	 * Number of object types in this NIF file.
 	 */
diff --git a/include/niflib.h b/include/niflib.h
index 38381caf..91323f91 100644
--- a/include/niflib.h
+++ b/include/niflib.h
@@ -84,6 +84,34 @@ enum ExportOptions {
 	EXPORT_KF_MULTI = 4 /*!< multiple KF */
 };
 
+//--Structures--//
+
+struct NifInfo {
+	NifInfo() : version(VER_4_0_0_2), userVersion(0), userVersion2(0), endian(INFO_BIG_ENDIAN) {}
+	NifInfo( unsigned version, unsigned userVersion = 0, unsigned userVersion2 = 0) {
+		this->version = version;
+		this->userVersion = userVersion;
+		this->userVersion2 = userVersion2;
+		endian = INFO_BIG_ENDIAN;
+	}
+	//TODO: Implement endian support
+	enum EndianType {
+		INFO_BIG_ENDIAN = 0,
+		INFO_LITTLE_ENDIAN = 1
+	}; 
+	unsigned version;
+	unsigned userVersion;
+	unsigned  userVersion2;
+	/*! This is not yet supported. */
+	EndianType endian;
+	/*! This is only supported in Oblivion.  It contains the name of the person who created the NIF file. */
+	string creator;
+	/*! This is only supported in Oblivion.  It seems to contiain the type of script or program used to export the file. */
+	string exportInfo1;
+	/*! This is only supported in Oblivion.  It seems to contain the more specific script or options of the above. */
+	string exportInfo2;
+};
+
 //--Main Functions--//
 
 /*!
@@ -121,6 +149,7 @@ NIFLIB_API unsigned int CheckNifHeader( string const & file_name );
 /*!
  * Reads the given file by file name and returns a vector of block references
  * \param file_name The name of the file to load, or the complete path if it is not in the working directory.
+ * \param info Optionally, a NifInfo structure pointer can be passed in, and it will be filled with information from the header of the NIF file.
  * \return A vector of block references that point to all the blocks read from the Nif file.
  * 
  * <b>Example:</b> 
@@ -135,18 +164,20 @@ NIFLIB_API unsigned int CheckNifHeader( string const & file_name );
  * 
  * \sa ReadNifTree, WriteNifTree
  */
-NIFLIB_API vector< Ref<NiObject> > ReadNifList( string const & file_name );
+NIFLIB_API vector< Ref<NiObject> > ReadNifList( string const & file_name, NifInfo * info = NULL );
 
 /*!
  * Reads the given input stream and returns a vector of block references
  * \param stream The input stream to read NIF data from.
+ * \param info Optionally, a NifInfo structure pointer can be passed in, and it will be filled with information from the header of the NIF file.
  * \return A vector of block references that point to all the blocks read from the stream.
  */
-NIFLIB_API vector< Ref<NiObject> > ReadNifList( istream & in );
+NIFLIB_API vector< Ref<NiObject> > ReadNifList( istream & in, NifInfo * info = NULL );
 
 /*!
  * Reads the given file by file name and returns a reference to the root block.
  * \param file_name The name of the file to load, or the complete path if it is not in the working directory.
+ * \param info Optionally, a NifInfo structure pointer can be passed in, and it will be filled with information from the header of the NIF file.
  * \return A block reference that points to the root of tree of data blocks contained in the NIF file.
  * 
  * <b>Example:</b> 
@@ -161,21 +192,21 @@ NIFLIB_API vector< Ref<NiObject> > ReadNifList( istream & in );
  * 
  * \sa ReadNifList, WriteNifTree
  */
-NIFLIB_API Ref<NiObject> ReadNifTree( string const & file_name );
+NIFLIB_API Ref<NiObject> ReadNifTree( string const & file_name, NifInfo * info = NULL );
 
 /*!
  * Reads the given input stream and returns a reference to the root block.
  * \param stream The input stream to read NIF data from.
+ * \param info Optionally, a NifInfo structure pointer can be passed in, and it will be filled with information from the header of the NIF file.
  * \return A block reference that points to the root of the tree of data blocks contained in the NIF file.
  */
-NIFLIB_API Ref<NiObject> ReadNifTree( istream & in );
+NIFLIB_API Ref<NiObject> ReadNifTree( istream & in, NifInfo * info = NULL );
 
 /*!
  * Creates a new NIF file of the given file name by crawling through the data tree starting with the root block given.
  * \param file_name The desired file name for the new NIF file.  The path is relative to the working directory unless a full path is specified.
  * \param root The root block to start from when writing out the NIF file.  All decedents of this block will be written to the file in tree-descending order.
- * \param version The version of the NIF format to use when writing a file.  Default is version 4.0.0.2.
- * \param user_version Some companies implement special extentions to the format which can be specified here.
+ * \param info A NifInfo structure that contains information such as the version of the NIF file to create.
  * 
  * <b>Example:</b> 
  * \code
@@ -191,25 +222,25 @@ NIFLIB_API Ref<NiObject> ReadNifTree( istream & in );
  * 
  * \sa ReadNifList, WriteNifTree
  */
-NIFLIB_API void WriteNifTree( string const & file_name, Ref<NiObject> const & root, unsigned int version = VER_4_0_0_2, unsigned int user_version = 0 );
+NIFLIB_API void WriteNifTree( string const & file_name, Ref<NiObject> const & root, NifInfo & info );
 
 /*!
  * Writes a nif tree to an ostream starting at the given root block.
  * \param stream The output stream to write the NIF data to.
  * \param root The root block to start from when writing out the NIF data.  All decedents of this block will be written to the stream in tree-descending order.
- * \param version The version of the NIF format to use when writing a file.  Default is version 4.0.0.2.
+ * \param info A NifInfo structure that contains information such as the version of the NIF file to create.
  */
-NIFLIB_API void WriteNifTree( ostream & stream, Ref<NiObject> const & root, unsigned int version = VER_4_0_0_2, unsigned int user_version = 0 );
+NIFLIB_API void WriteNifTree( ostream & stream, Ref<NiObject> const & root, NifInfo & info );
 
 /*!
  * Writes a bunch of files given a base file name, and a pointer to the root block of the Nif file tree.
  * \param file_name The desired file name for the base NIF file. This name serves as the basis for the names of any Kf files and Kfm files as well.  The path is relative to the working directory unless a full path is specified.
  * \param root The root block to start from when writing out the NIF file.
- * \param version The version of the NIF format to use when writing a file.
+ * \param info A NifInfo structure that contains information such as the version of the NIF file to create.
  * \param export_files What files to write: NIF, NIF + KF + KFM, NIF + KF's + KFM, KF only, KF's only
  * \param kf_type The KF type (Morrowind style, DAoC style, CivIV style, ...)
  */
-NIFLIB_API void WriteFileGroup( string const & file_name, Ref<NiObject> const & root, unsigned int version = VER_4_0_0_2, unsigned int user_version = 0, ExportOptions export_files = EXPORT_NIF, NifGame kf_type = KF_MW);
+NIFLIB_API void WriteFileGroup( string const & file_name, Ref<NiObject> const & root, NifInfo & info, ExportOptions export_files = EXPORT_NIF, NifGame kf_type = KF_MW);
 
 /*!
  * Creates a clone of an entire tree of objects.
@@ -218,7 +249,7 @@ NIFLIB_API void WriteFileGroup( string const & file_name, Ref<NiObject> const &
  * \param user_version The user version of the NIF format to use when writing a file.  Default is user version 0.
  * \return The root of the new cloned tree.
  */
-NIFLIB_API Ref<NiObject> CloneNifTree( Ref<NiObject> const & root, unsigned int version = VER_4_0_0_2, unsigned int user_version = 0 );
+NIFLIB_API Ref<NiObject> CloneNifTree( Ref<NiObject> const & root, unsigned version = 0xFFFFFFFF, unsigned user_version = 0 );
 
 
 //TODO:  Figure out how to fix this to work with the new system
@@ -227,9 +258,10 @@ NIFLIB_API Ref<NiObject> CloneNifTree( Ref<NiObject> const & root, unsigned int
  * \param target The root block of the first Nif tree to merge.
  * \param right The root block of the second Nif tree to merge.
  * \param version The version of the nif format to use during the clone operation on the right-hand tree.  The default is the highest version availiable.
+ * \param user_version The user version to use during the clone operation.
  */
 //NIFLIB_API void MergeNifTrees( NiNodeRef target, NiAVObjectRef right, unsigned int version = 0xFFFFFFFF );
-NIFLIB_API void MergeNifTrees( const Ref<NiNode> & target, const Ref<NiControllerSequence> & right, unsigned int version = 0xFFFFFFFF, unsigned int user_version = 0 );
+NIFLIB_API void MergeNifTrees( const Ref<NiNode> & target, const Ref<NiControllerSequence> & right, unsigned version = 0xFFFFFFFF, unsigned user_version = 0  );
 
 /*! 
  * Traverses a tree of NIF objects, attempting to move each skeleton root
diff --git a/src/gen/Header.cpp b/src/gen/Header.cpp
index ba4c35dd..7dbfe23a 100644
--- a/src/gen/Header.cpp
+++ b/src/gen/Header.cpp
@@ -29,9 +29,9 @@ void Header::Read( istream& in ) {
 	};
 	if ( version >= 0x0A000102 ) {
 		if ( (userVersion != 0) ) {
-			NifStream( creator_, in, version );
-			NifStream( exportType_, in, version );
-			NifStream( exportScript_, in, version );
+			NifStream( creator, in, version );
+			NifStream( exportInfo1, in, version );
+			NifStream( exportInfo2, in, version );
 		};
 	};
 	if ( version >= 0x0A000100 ) {
@@ -70,9 +70,9 @@ void Header::Write( ostream& out ) const {
 	};
 	if ( version >= 0x0A000102 ) {
 		if ( (userVersion != 0) ) {
-			NifStream( creator_, out, version );
-			NifStream( exportType_, out, version );
-			NifStream( exportScript_, out, version );
+			NifStream( creator, out, version );
+			NifStream( exportInfo1, out, version );
+			NifStream( exportInfo2, out, version );
 		};
 	};
 	if ( version >= 0x0A000100 ) {
@@ -99,9 +99,9 @@ string Header::asString( bool verbose ) const {
 	out << "  Unknown Int 1:  " << unknownInt1 << endl;
 	if ( (userVersion != 0) ) {
 		out << "    User Version 2:  " << userVersion2 << endl;
-		out << "    Creator?:  " << creator_ << endl;
-		out << "    Export Type?:  " << exportType_ << endl;
-		out << "    Export Script?:  " << exportScript_ << endl;
+		out << "    Creator:  " << creator << endl;
+		out << "    Export Info 1:  " << exportInfo1 << endl;
+		out << "    Export Info 2:  " << exportInfo2 << endl;
 	};
 	out << "  Num Block Types:  " << numBlockTypes << endl;
 	for (uint i1 = 0; i1 < blockTypes.size(); i1++) {
diff --git a/src/gen/enums.cpp b/src/gen/enums.cpp
index 699ca2a5..8b493c92 100644
--- a/src/gen/enums.cpp
+++ b/src/gen/enums.cpp
@@ -3,7 +3,6 @@ All rights reserved.  Please see niflib.h for licence. */
 
 #include <string>
 #include <iostream>
-
 #include "../../include/NIF_IO.h"
 #include "../../include/gen/enums.h"
 #include "../../include/gen/enums_intl.h"
diff --git a/src/gen/obj_impl.cpp b/src/gen/obj_impl.cpp
index 86f2f94b..0c257b9c 100644
--- a/src/gen/obj_impl.cpp
+++ b/src/gen/obj_impl.cpp
@@ -1151,7 +1151,7 @@ void NiDynamicEffect::InternalRead( istream& in, list<uint> & link_stack, unsign
 	if ( version >= 0x0A020000 ) {
 		NifStream( switchState, in, version );
 	};
-		NifStream( numAffectedNodes, in, version );
+	NifStream( numAffectedNodes, in, version );
 	if ( version >= 0x0A010000 ) {
 		affectedNodes.resize(numAffectedNodes);
 		for (uint i2 = 0; i2 < affectedNodes.size(); i2++) {
@@ -1173,7 +1173,7 @@ void NiDynamicEffect::InternalWrite( ostream& out, map<NiObjectRef,uint> link_ma
 	if ( version >= 0x0A020000 ) {
 		NifStream( switchState, out, version );
 	};
-		NifStream( numAffectedNodes, out, version );
+	NifStream( numAffectedNodes, out, version );
 	if ( version >= 0x0A010000 ) {
 		for (uint i2 = 0; i2 < affectedNodes.size(); i2++) {
 			if ( affectedNodes[i2] != NULL )
@@ -11738,30 +11738,30 @@ void NiTexturingProperty::InternalRead( istream& in, list<uint> & link_stack, un
 	if ( (textureCount == 8) ) {
 		NifStream( hasDecal1Texture, in, version );
 	};
-		if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
-			NifStream( block_num, in, version );
-			link_stack.push_back( block_num );
-			NifStream( decal1Texture.clampMode, in, version );
-			NifStream( decal1Texture.filterMode, in, version );
-			NifStream( decal1Texture.textureSet, in, version );
-			if ( version <= 0x0A020000 ) {
-				NifStream( decal1Texture.ps2L, in, version );
-				NifStream( decal1Texture.ps2K, in, version );
-			};
-			if ( version <= 0x0401000C ) {
-				NifStream( decal1Texture.unknown1, in, version );
-			};
-			if ( version >= 0x0A010000 ) {
-				NifStream( decal1Texture.hasTextureTransform, in, version );
-				if ( (decal1Texture.hasTextureTransform != 0) ) {
-					NifStream( decal1Texture.translation, in, version );
-					NifStream( decal1Texture.tiling, in, version );
-					NifStream( decal1Texture.wRotation, in, version );
-					NifStream( decal1Texture.transformType_, in, version );
-					NifStream( decal1Texture.centerOffset, in, version );
-				};
+	if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
+		NifStream( block_num, in, version );
+		link_stack.push_back( block_num );
+		NifStream( decal1Texture.clampMode, in, version );
+		NifStream( decal1Texture.filterMode, in, version );
+		NifStream( decal1Texture.textureSet, in, version );
+		if ( version <= 0x0A020000 ) {
+			NifStream( decal1Texture.ps2L, in, version );
+			NifStream( decal1Texture.ps2K, in, version );
+		};
+		if ( version <= 0x0401000C ) {
+			NifStream( decal1Texture.unknown1, in, version );
+		};
+		if ( version >= 0x0A010000 ) {
+			NifStream( decal1Texture.hasTextureTransform, in, version );
+			if ( (decal1Texture.hasTextureTransform != 0) ) {
+				NifStream( decal1Texture.translation, in, version );
+				NifStream( decal1Texture.tiling, in, version );
+				NifStream( decal1Texture.wRotation, in, version );
+				NifStream( decal1Texture.transformType_, in, version );
+				NifStream( decal1Texture.centerOffset, in, version );
 			};
 		};
+	};
 	if ( version >= 0x0A000100 ) {
 		NifStream( numShaderTextures, in, version );
 		shaderTextures.resize(numShaderTextures);
@@ -11999,32 +11999,32 @@ void NiTexturingProperty::InternalWrite( ostream& out, map<NiObjectRef,uint> lin
 	if ( (textureCount == 8) ) {
 		NifStream( hasDecal1Texture, out, version );
 	};
-		if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
-			if ( decal1Texture.source != NULL )
-				NifStream( link_map[StaticCast<NiObject>(decal1Texture.source)], out, version );
-			else
-				NifStream( 0xffffffff, out, version );
-			NifStream( decal1Texture.clampMode, out, version );
-			NifStream( decal1Texture.filterMode, out, version );
-			NifStream( decal1Texture.textureSet, out, version );
-			if ( version <= 0x0A020000 ) {
-				NifStream( decal1Texture.ps2L, out, version );
-				NifStream( decal1Texture.ps2K, out, version );
-			};
-			if ( version <= 0x0401000C ) {
-				NifStream( decal1Texture.unknown1, out, version );
-			};
-			if ( version >= 0x0A010000 ) {
-				NifStream( decal1Texture.hasTextureTransform, out, version );
-				if ( (decal1Texture.hasTextureTransform != 0) ) {
-					NifStream( decal1Texture.translation, out, version );
-					NifStream( decal1Texture.tiling, out, version );
-					NifStream( decal1Texture.wRotation, out, version );
-					NifStream( decal1Texture.transformType_, out, version );
-					NifStream( decal1Texture.centerOffset, out, version );
-				};
+	if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
+		if ( decal1Texture.source != NULL )
+			NifStream( link_map[StaticCast<NiObject>(decal1Texture.source)], out, version );
+		else
+			NifStream( 0xffffffff, out, version );
+		NifStream( decal1Texture.clampMode, out, version );
+		NifStream( decal1Texture.filterMode, out, version );
+		NifStream( decal1Texture.textureSet, out, version );
+		if ( version <= 0x0A020000 ) {
+			NifStream( decal1Texture.ps2L, out, version );
+			NifStream( decal1Texture.ps2K, out, version );
+		};
+		if ( version <= 0x0401000C ) {
+			NifStream( decal1Texture.unknown1, out, version );
+		};
+		if ( version >= 0x0A010000 ) {
+			NifStream( decal1Texture.hasTextureTransform, out, version );
+			if ( (decal1Texture.hasTextureTransform != 0) ) {
+				NifStream( decal1Texture.translation, out, version );
+				NifStream( decal1Texture.tiling, out, version );
+				NifStream( decal1Texture.wRotation, out, version );
+				NifStream( decal1Texture.transformType_, out, version );
+				NifStream( decal1Texture.centerOffset, out, version );
 			};
 		};
+	};
 	if ( version >= 0x0A000100 ) {
 		NifStream( numShaderTextures, out, version );
 		for (uint i2 = 0; i2 < shaderTextures.size(); i2++) {
@@ -12320,17 +12320,17 @@ void NiTexturingProperty::InternalFixLinks( const vector<NiObjectRef> & objects,
 			decal0Texture.source = NULL;
 		link_stack.pop_front();
 	};
-		if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
-			if (link_stack.empty())
-				throw runtime_error("Trying to pop a link from empty stack. This is probably a bug.");
-			if (link_stack.front() != 0xffffffff) {
-				decal1Texture.source = DynamicCast<NiSourceTexture>(objects[link_stack.front()]);
-				if ( decal1Texture.source == NULL )
-					throw runtime_error("Link could not be cast to required type during file read. This NIF file may be invalid or improperly understood.");
-			} else
-				decal1Texture.source = NULL;
-			link_stack.pop_front();
-		};
+	if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
+		if (link_stack.empty())
+			throw runtime_error("Trying to pop a link from empty stack. This is probably a bug.");
+		if (link_stack.front() != 0xffffffff) {
+			decal1Texture.source = DynamicCast<NiSourceTexture>(objects[link_stack.front()]);
+			if ( decal1Texture.source == NULL )
+				throw runtime_error("Link could not be cast to required type during file read. This NIF file may be invalid or improperly understood.");
+		} else
+			decal1Texture.source = NULL;
+		link_stack.pop_front();
+	};
 	if ( version >= 0x0A000100 ) {
 		for (uint i2 = 0; i2 < shaderTextures.size(); i2++) {
 			if ( (shaderTextures[i2].isUsed != 0) ) {
diff --git a/src/niflib.cpp b/src/niflib.cpp
index d13542ab..e921dbe3 100644
--- a/src/niflib.cpp
+++ b/src/niflib.cpp
@@ -75,7 +75,7 @@ NiObjectRef CreateObject( string block_type ) {
 }
 
 //Reads the given file by file name and returns a reference to the root block
-NiObjectRef ReadNifTree( string const & file_name ) {
+NiObjectRef ReadNifTree( string const & file_name, NifInfo * info ) {
 	//Read block list
 	//cout << "File name:  " << file_name << endl;
 	vector<NiObjectRef> blocks = ReadNifList( file_name );
@@ -83,7 +83,7 @@ NiObjectRef ReadNifTree( string const & file_name ) {
 }
 
 //Reads the given input stream and returns a reference to the root block
-NiObjectRef ReadNifTree( istream & in ) {
+NiObjectRef ReadNifTree( istream & in, NifInfo * info ) {
 	//Read block list
 	vector<NiObjectRef> blocks = ReadNifList( in );
 	return FindRoot( blocks );
@@ -144,7 +144,7 @@ unsigned int CheckNifHeader( string const & file_name ) {
 }
 
 //Reads the given file by file name and returns a vector of block references
-vector<NiObjectRef> ReadNifList( string const & file_name ) {
+vector<NiObjectRef> ReadNifList( string const & file_name, NifInfo * info ) {
 
 	//--Open File--//
 	ifstream in( file_name.c_str(), ifstream::binary );
@@ -153,7 +153,7 @@ vector<NiObjectRef> ReadNifList( string const & file_name ) {
 }
 
 //Reads the given input stream and returns a vector of block references
-vector<NiObjectRef> ReadNifList( istream & in ) {
+vector<NiObjectRef> ReadNifList( istream & in, NifInfo * info ) {
 
 	//--Read Header--//
 	Header header;
@@ -161,6 +161,21 @@ vector<NiObjectRef> ReadNifList( istream & in ) {
 	//Read header.
 	header.Read( in );
 
+	//If NifInfo structure is provided, fill it with info from header
+	if ( info != NULL ) {
+		info->version = header.version;
+		info->userVersion = header.userVersion;
+		info->userVersion2 = header.userVersion2;
+		if ( header.endianType == 0) {
+			info->endian = NifInfo::INFO_BIG_ENDIAN;
+		} else {
+			info->endian = NifInfo::INFO_LITTLE_ENDIAN;
+		}
+		info->creator = header.creator.str;
+		info->exportInfo1 = header.exportInfo1.str;
+		info->exportInfo2 = header.exportInfo2.str;
+	}
+
 #ifdef DEBUG_HEADER_FOOTER
 	//Print debug output for header
 	cout << header.asString();
@@ -290,7 +305,7 @@ vector<NiObjectRef> ReadNifList( istream & in ) {
 }
 
 // Writes a valid Nif File given an ostream, a list to the root objects of a file tree
-void WriteNifTree( ostream & out, list<NiObjectRef> const & roots, unsigned int version, unsigned int user_version ) {
+void WriteNifTree( ostream & out, list<NiObjectRef> const & roots, NifInfo & info ) {
 	// Walk tree, resetting all block numbers
 	//int block_count = ResetBlockNums( 0, root_block );
 	
@@ -313,11 +328,18 @@ void WriteNifTree( ostream & out, list<NiObjectRef> const & roots, unsigned int
 		types[it->second] = it->first;
 	}
 
+	unsigned version = info.version;
+	unsigned user_version = info.userVersion;
+
 	//--Write Header--//
 	Header header;
-	header.version = version;
-	header.userVersion = user_version;
-   header.userVersion2 = user_version;
+	header.version = info.version;
+	header.userVersion = info.userVersion;
+	header.userVersion2 = info.userVersion2;
+	header.endianType = byte(info.endian);
+	header.creator.str = info.creator;
+	header.exportInfo1.str = info.exportInfo1;
+	header.exportInfo2.str = info.exportInfo2;
 	
 	//Set Type Names
 	header.blockTypes.resize( types.size() );
@@ -383,33 +405,33 @@ void WriteNifTree( ostream & out, list<NiObjectRef> const & roots, unsigned int
 }
 
 // Writes a valid Nif File given a file name, a pointer to the root block of a file tree
-void WriteNifTree( string const & file_name, NiObjectRef const & root_block, unsigned int version, unsigned int user_version ) {
+void WriteNifTree( string const & file_name, NiObjectRef const & root_block, NifInfo & info ) {
    //Open output file
    ofstream out( file_name.c_str(), ofstream::binary );
 
    list<NiObjectRef> roots;
    roots.push_back(root_block);
-   WriteNifTree( out, roots, version, user_version );
+   WriteNifTree( out, roots, info );
 
    //Close file
    out.close();
 }
 
-void WriteNifTree( string const & file_name, list<NiObjectRef> const & roots, unsigned int version, unsigned int user_version ) {
+void WriteNifTree( string const & file_name, list<NiObjectRef> const & roots, NifInfo & info ) {
    //Open output file
    ofstream out( file_name.c_str(), ofstream::binary );
 
-   WriteNifTree( out, roots, version, user_version );
+   WriteNifTree( out, roots, info );
 
    //Close file
    out.close();
 }
 
 // Writes a valid Nif File given an ostream, a pointer to the root object of a file tree
-void WriteNifTree( ostream & out, NiObjectRef const & root, unsigned int version, unsigned int user_version ) {
+void WriteNifTree( ostream & out, NiObjectRef const & root, NifInfo & info ) {
    list<NiObjectRef> roots;
    roots.push_back(root);
-   WriteNifTree( out, roots, version, user_version );
+   WriteNifTree( out, roots, info );
 }
 
 void EnumerateObjects( NiObjectRef const & root, map<Type*,uint> & type_map, map<NiObjectRef, uint> & link_map, bool reverse ) {
@@ -555,7 +577,7 @@ static std::string CreateFileName(std::string name) {
  * \param kfm The KFM structure (if required by style).
  * \param kf_type What type of keyframe tree to write (Morrowind style, DAoC style, ...).
  */
-static void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, list<NiObjectRef> & xkf_roots, Kfm & kfm, int kf_type, unsigned int version, unsigned int user_version ) {
+static void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, list<NiObjectRef> & xkf_roots, Kfm & kfm, int kf_type, NifInfo & info ) {
 	// Do we have animation groups (a NiTextKeyExtraData block)?
 	// If so, create XNif and XKf trees.
 	NiObjectRef txtkey = GetObjectByType( root_block, NiTextKeyExtraData::TypeConst() );
@@ -567,23 +589,23 @@ static void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_roo
 		if ( kf_type == KF_MW ) {
 			// Construct the XNif file...
 
-         xnif_root = CloneNifTree(root_block, version, user_version);
-			
-         // Now search and locate newer timeframe controllers and convert to keyframecontrollers
-         list<NiObjectRef> mgrs = GetAllObjectsByType( xnif_root, NiControllerManager::TypeConst() );
-         for ( list<NiObjectRef>::iterator it = mgrs.begin(); it != mgrs.end(); ++it) {
-            NiControllerManagerRef mgr = DynamicCast<NiControllerManager>(*it);
-            if ( mgr == NULL ) {
-               continue;
-            }
-            NiObjectNETRef target = mgr->GetTarget();
-            target->RemoveController( StaticCast<NiTimeController>(mgr) );
-            vector<NiControllerSequenceRef> seqs = mgr->GetControllerSequences();
-            for (vector<NiControllerSequenceRef>::iterator itr = seqs.begin(); itr != seqs.end(); ++itr) {
-               NiControllerSequenceRef seq = (*itr);
-               MergeNifTrees(DynamicCast<NiNode>(target), seq, version, user_version);
-            }
-         }
+			xnif_root = CloneNifTree( root_block, info.version, info.userVersion );
+				
+			// Now search and locate newer timeframe controllers and convert to keyframecontrollers
+			list<NiObjectRef> mgrs = GetAllObjectsByType( xnif_root, NiControllerManager::TypeConst() );
+			for ( list<NiObjectRef>::iterator it = mgrs.begin(); it != mgrs.end(); ++it) {
+				NiControllerManagerRef mgr = DynamicCast<NiControllerManager>(*it);
+				if ( mgr == NULL ) {
+					continue;
+				}
+				NiObjectNETRef target = mgr->GetTarget();
+				target->RemoveController( StaticCast<NiTimeController>(mgr) );
+				vector<NiControllerSequenceRef> seqs = mgr->GetControllerSequences();
+				for (vector<NiControllerSequenceRef>::iterator itr = seqs.begin(); itr != seqs.end(); ++itr) {
+					NiControllerSequenceRef seq = (*itr);
+					MergeNifTrees(DynamicCast<NiNode>(target), seq, info.version, info.userVersion );
+				}
+			 }
 
 			// Now the XKf file...
 			// Create xkf root header.
@@ -605,39 +627,39 @@ static void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_roo
 				NiKeyframeControllerRef key_controller;
 				for ( list<NiTimeControllerRef>::iterator it = controllers.begin(); it != controllers.end(); ++it ) {
 
-               if ((*it)->IsDerivedType(NiKeyframeController::TypeConst())) {
-                  key_controller = StaticCast<NiKeyframeController>(*it);
-               } else if ((*it)->IsDerivedType(NiTransformController::TypeConst())) {
-                  NiTransformControllerRef trans = StaticCast<NiTransformController>(*it);
-                  NiTransformInterpolatorRef interp = DynamicCast<NiTransformInterpolator>(trans->GetInterpolator());
-                  if (interp != NULL) {
-                     NiTransformDataRef transData = interp->GetData();
-                     if (transData != NULL) {
-                        NiKeyframeDataRef data = new NiKeyframeData();
-                        data->SetRotateType( transData->GetRotateType() );
-                        data->SetTranslateType( transData->GetTranslateType() );
-                        data->SetScaleType( transData->GetScaleType() );
-                        data->SetXRotateType( transData->GetXRotateType() );
-                        data->SetYRotateType( transData->GetYRotateType() );
-                        data->SetZRotateType( transData->GetZRotateType() );
-                        data->SetTranslateKeys( transData->GetTranslateKeys() );
-                        data->SetQuatRotateKeys( transData->GetQuatRotateKeys() );
-                        data->SetScaleKeys( transData->GetScaleKeys() );
-                        data->SetXRotateKeys( transData->GetXRotateKeys() );
-                        data->SetYRotateKeys( transData->GetYRotateKeys() );
-                        data->SetZRotateKeys( transData->GetZRotateKeys() );
-
-                        key_controller = new NiKeyframeController();
-                        key_controller->SetFlags( trans->GetFlags() );
-                        key_controller->SetFrequency( trans->GetFrequency() );
-                        key_controller->SetPhase( trans->GetPhase() );
-                        key_controller->SetStartTime( trans->GetStartTime() );
-                        key_controller->SetStopTime( trans->GetStopTime() );
-                        key_controller->SetData( data );
-                        break;
-                     }
-                  }
-               }
+					if ((*it)->IsDerivedType(NiKeyframeController::TypeConst())) {
+						key_controller = StaticCast<NiKeyframeController>(*it);
+					} else if ((*it)->IsDerivedType(NiTransformController::TypeConst())) {
+						NiTransformControllerRef trans = StaticCast<NiTransformController>(*it);
+						NiTransformInterpolatorRef interp = DynamicCast<NiTransformInterpolator>(trans->GetInterpolator());
+						if (interp != NULL) {
+							NiTransformDataRef transData = interp->GetData();
+							if (transData != NULL) {
+								NiKeyframeDataRef data = new NiKeyframeData();
+								data->SetRotateType( transData->GetRotateType() );
+								data->SetTranslateType( transData->GetTranslateType() );
+								data->SetScaleType( transData->GetScaleType() );
+								data->SetXRotateType( transData->GetXRotateType() );
+								data->SetYRotateType( transData->GetYRotateType() );
+								data->SetZRotateType( transData->GetZRotateType() );
+								data->SetTranslateKeys( transData->GetTranslateKeys() );
+								data->SetQuatRotateKeys( transData->GetQuatRotateKeys() );
+								data->SetScaleKeys( transData->GetScaleKeys() );
+								data->SetXRotateKeys( transData->GetXRotateKeys() );
+								data->SetYRotateKeys( transData->GetYRotateKeys() );
+								data->SetZRotateKeys( transData->GetZRotateKeys() );
+
+								key_controller = new NiKeyframeController();
+								key_controller->SetFlags( trans->GetFlags() );
+								key_controller->SetFrequency( trans->GetFrequency() );
+								key_controller->SetPhase( trans->GetPhase() );
+								key_controller->SetStartTime( trans->GetStartTime() );
+								key_controller->SetStopTime( trans->GetStopTime() );
+								key_controller->SetData( data );
+								break;
+							}
+						}
+					}
 				}
 
 				//If this node has no keyframe controller, put it in the list
@@ -650,39 +672,39 @@ static void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_roo
 				//Add string data				
 				NiStringExtraDataRef nodextra = new NiStringExtraData;
 				nodextra->SetData( it->first->GetName() );
-				xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(nodextra), version );
+				xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(nodextra), info.version );
 
-            NiKeyframeControllerRef controller = it->second;
-            (it->first)->RemoveController( StaticCast<NiTimeController>(controller) );
+				NiKeyframeControllerRef controller = it->second;
+				(it->first)->RemoveController( StaticCast<NiTimeController>(controller) );
 
 				xkf_stream_helper->AddController( StaticCast<NiTimeController>(controller) );
 			}
 
 			// Add a copy of the NiTextKeyExtraData block to the XKf header.
 			NiTextKeyExtraDataRef xkf_txtkey_block = new NiTextKeyExtraData;
-         xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(xkf_txtkey_block), version );
+			xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(xkf_txtkey_block), info.version );
 			xkf_txtkey_block->SetKeys( txtkey_block->GetKeys() );
 
-      } else if (kf_type == KF_CIV4) {
-         // Construct the Nif file without transform controllers ...
-         xnif_root = CloneNifTree(root_block, version, user_version);
-
-         list<NiObjectRef> mgrs = GetAllObjectsByType( xnif_root, NiControllerManager::TypeConst() );
-         for ( list<NiObjectRef>::iterator it = mgrs.begin(); it != mgrs.end(); ++it) {
-            NiControllerManagerRef mgr = DynamicCast<NiControllerManager>(*it);
-            if ( mgr == NULL ) {
-               continue;
-            }
-            NiObjectNETRef target = mgr->GetTarget();
-            target->RemoveController( StaticCast<NiTimeController>(mgr) );
-            vector<NiControllerSequenceRef> seqs = mgr->GetControllerSequences();
-            for (vector<NiControllerSequenceRef>::iterator itr = seqs.begin(); itr != seqs.end(); ++itr) {
-               xkf_roots.push_back( StaticCast<NiObject>(*itr) );
-            }
-         }
+		} else if (kf_type == KF_CIV4) {
+			// Construct the Nif file without transform controllers ...
+			xnif_root = CloneNifTree( root_block, info.version, info.userVersion );
 
-      } else
+			list<NiObjectRef> mgrs = GetAllObjectsByType( xnif_root, NiControllerManager::TypeConst() );
+			for ( list<NiObjectRef>::iterator it = mgrs.begin(); it != mgrs.end(); ++it) {
+				NiControllerManagerRef mgr = DynamicCast<NiControllerManager>(*it);
+				if ( mgr == NULL ) {
+				   continue;
+				}
+				NiObjectNETRef target = mgr->GetTarget();
+				target->RemoveController( StaticCast<NiTimeController>(mgr) );
+				vector<NiControllerSequenceRef> seqs = mgr->GetControllerSequences();
+				for (vector<NiControllerSequenceRef>::iterator itr = seqs.begin(); itr != seqs.end(); ++itr) {
+				   xkf_roots.push_back( StaticCast<NiObject>(*itr) );
+				}
+			}
+		} else {
 			throw runtime_error("KF splitting for the requested game is not yet implemented.");
+		}
 	} else {
 		// no animation groups: nothing to do
 		xnif_root = root_block;
@@ -700,7 +722,7 @@ static void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_roo
 //};
 
 //TODO:  This was written by Amorilia.  Figure out how to fix it.
-void WriteFileGroup( string const & file_name, NiObjectRef const & root_block, unsigned int version, unsigned int user_version, ExportOptions export_files, NifGame kf_type ) {
+void WriteFileGroup( string const & file_name, NiObjectRef const & root_block, NifInfo & info, ExportOptions export_files, NifGame kf_type ) {
 	// Get base filename.
 	uint file_name_slash = uint(file_name.rfind("\\") + 1);
 	string file_name_path = file_name.substr(0, file_name_slash);
@@ -710,19 +732,19 @@ void WriteFileGroup( string const & file_name, NiObjectRef const & root_block, u
 	
 	// Deal with the simple case first
 	if ( export_files == EXPORT_NIF )
-		WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version, user_version ); // simply export the NIF file!
+		WriteNifTree( file_name_path + file_name_base + ".nif", root_block, info ); // simply export the NIF file!
 	// Now consider all other cases
 	else if ( kf_type == KF_MW ) {
 		if ( export_files == EXPORT_NIF_KF ) {
 			// for Morrowind we must also write the full NIF file
-			WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version, user_version ); // simply export the NIF file!
+			WriteNifTree( file_name_path + file_name_base + ".nif", root_block, info ); // simply export the NIF file!
 			NiObjectRef xnif_root;
 			list<NiObjectRef> xkf_roots;
 			Kfm kfm; // dummy
-			SplitNifTree( root_block, xnif_root, xkf_roots, kfm, kf_type, version, user_version );
+			SplitNifTree( root_block, xnif_root, xkf_roots, kfm, kf_type, info );
 			if ( xnif_root != NULL && !xkf_roots.empty()) {
-				WriteNifTree( file_name_path + "x" + file_name_base + ".nif", xnif_root, version, user_version );
-				WriteNifTree( file_name_path + "x" + file_name_base + ".kf", xkf_roots.front(), version, user_version );
+				WriteNifTree( file_name_path + "x" + file_name_base + ".nif", xnif_root, info );
+				WriteNifTree( file_name_path + "x" + file_name_base + ".kf", xkf_roots.front(), info );
 			};
 		} else
 			throw runtime_error("Invalid export option.");
@@ -731,19 +753,19 @@ void WriteFileGroup( string const & file_name, NiObjectRef const & root_block, u
       NiObjectRef xnif_root;
       list<NiObjectRef> xkf_roots;
       Kfm kfm; // dummy
-      SplitNifTree( root_block, xnif_root, xkf_roots, kfm, kf_type, version, user_version );
+	  SplitNifTree( root_block, xnif_root, xkf_roots, kfm, kf_type, info );
       if ( export_files == EXPORT_NIF || export_files == EXPORT_NIF_KF || export_files == EXPORT_NIF_KF_MULTI ) {
-         WriteNifTree( file_name_path + file_name_base + ".nif", xnif_root, version, user_version );
+         WriteNifTree( file_name_path + file_name_base + ".nif", xnif_root, info );
       }
       if ( export_files == EXPORT_NIF_KF || export_files == EXPORT_KF ) {
-         WriteNifTree( file_name_path + file_name_base + ".kf", xkf_roots, version, user_version );
+         WriteNifTree( file_name_path + file_name_base + ".kf", xkf_roots, info );
       } else if ( export_files == EXPORT_NIF_KF_MULTI || export_files == EXPORT_KF_MULTI ) {
          for ( list<NiObjectRef>::iterator it = xkf_roots.begin(); it != xkf_roots.end(); ++it ) {
             NiControllerSequenceRef seq = DynamicCast<NiControllerSequence>(*it);
             if (seq == NULL)
                continue;
             string path = file_name_path + file_name_base + "_" + CreateFileName(seq->GetTargetName()) + "_" + CreateFileName(seq->GetName()) + ".kf";
-            WriteNifTree( path, StaticCast<NiObject>(seq), version, user_version );
+            WriteNifTree( path, StaticCast<NiObject>(seq), info );
          }         
       }
    } else
@@ -845,7 +867,7 @@ void MergeSceneGraph( map<string,NiNodeRef> & name_map, const NiNodeRef & root,
 	}
 }
 
-void MergeNifTrees( NiNodeRef target, NiAVObjectRef right, unsigned int version ) {
+void MergeNifTrees( NiNodeRef target, NiAVObjectRef right, unsigned version, unsigned user_version ) {
 	//For now assume that both are normal Nif trees just to verify that it works
 
 	//Make a clone of the tree to add
@@ -867,7 +889,7 @@ void MergeNifTrees( NiNodeRef target, NiAVObjectRef right, unsigned int version
 }
 
 //Version for merging KF Trees rooted by a NiControllerSequence
-void MergeNifTrees( const Ref<NiNode> & target, const Ref<NiControllerSequence> & right, unsigned int version, unsigned int user_version ) {
+void MergeNifTrees( const Ref<NiNode> & target, const Ref<NiControllerSequence> & right, unsigned version, unsigned user_version ) {
 	//Map the node names
 	map<string,NiNodeRef> name_map;
 	MapNodeNames( name_map, target );
@@ -977,7 +999,7 @@ void MergeNifTrees( const Ref<NiNode> & target, const Ref<NiControllerSequence>
 }
 
 //Version for merging KF Trees rooted by a NiSequenceStreamHelper
-void MergeNifTrees( const Ref<NiNode> & target, const Ref<NiSequenceStreamHelper> & right, unsigned int version, unsigned int user_version ) {
+void MergeNifTrees( const Ref<NiNode> & target, const Ref<NiSequenceStreamHelper> & right, unsigned version, unsigned user_version ) {
 	//Map the node names
 	map<string,NiNodeRef> name_map;
 	MapNodeNames( name_map, target );
@@ -1028,12 +1050,12 @@ unsigned int GetVersion(string version){
    return outver;
 }
 
-Ref<NiObject> CloneNifTree( Ref<NiObject> const & root, unsigned int version, unsigned int user_version ) {
+Ref<NiObject> CloneNifTree( Ref<NiObject> const & root, unsigned version, unsigned user_version ) {
 	//Create a string stream to temporarily hold the state-save of this tree
 	stringstream tmp;
 
 	//Write the existing tree into the stringstream
-	WriteNifTree( tmp, root, version, user_version );
+	WriteNifTree( tmp, root, NifInfo(version, user_version) );
 
 	//Read the data back out of the stringstream, returning the new tree
 	return ReadNifTree( tmp );
-- 
GitLab