<commit_before>/* Copyright (c) 2005, NIF File Format Library and Tools
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above
     copyright notice, this list of conditions and the following
     disclaimer in the documentation and/or other materials provided
     with the distribution.

   * Neither the name of the NIF File Format Library and Tools
     project nor the names of its contributors may be used to endorse
     or promote products derived from this software without specific
     prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */

#include "niflib.h"
#include "NIF_Blocks.h"
#include "nif_attrs.h"
#include "kfm.h"
#include <exception>
#include <stdexcept>
using namespace std;

bool verbose = false;

//Stores the mapping between block names and factory function pointers to create them
typedef IBlock * (*blk_factory_func)();
bool global_block_map_init = false;
map<string, blk_factory_func> global_block_map;

//Temporary Global to test reference counting
unsigned int blocks_in_memory = 0;

//Utility Functions
void ReorderNifTree( vector<blk_ref> & blk_list, vector<string> & blk_types, blk_ref const & block );
void BuildUpBindPositions( blk_ref const & block );
blk_ref FindRoot( vector<blk_ref> const & blocks );
void RegisterBlockFactories ();

//--Function Bodies--//
void SetVerboseMode( bool val ) { verbose = val; }

blk_ref CreateBlock( string block_type ) {
	
	//Initialize the global block list if it hasn't been done yet
	if ( global_block_map_init == false ) {
		RegisterBlockFactories();
		global_block_map_init = true;
	}

	IBlock * block = NULL;

	map<string, blk_factory_func>::iterator it;
	it = global_block_map.find(block_type);

	if ( it != global_block_map.end() ) {
		//Requested type has been registered
		block = it->second();
	} else {
		//An unknown type has been encountered
		return blk_ref(-1); //Return null block_ref
		//block = new UnknownBlock( block_type );
	}
	
	return blk_ref(block);
}

//Reads the given file by file name and returns a reference to the root block
blk_ref ReadNifTree( string const & file_name ) {
	//Read block list
	vector<blk_ref> blocks = ReadNifList( file_name );
	return FindRoot( blocks );
}

//Reads the given input stream and returns a reference to the root block
blk_ref ReadNifTree( istream & in ) {
	//Read block list
	vector<blk_ref> blocks = ReadNifList( in );
	return FindRoot( blocks );
}

blk_ref FindRoot( vector<blk_ref> const & blocks ) {
	//--Look for a NiNode that has no parents--//

	//Find the first Node
	blk_ref root;
	for (uint i = 0; i < blocks.size(); ++i) {
		if ( blocks[i]->QueryInterface(ID_NODE) || blocks[i]->GetBlockType() == "NiPixelData" ) {
			root = blocks[i];
			break;
		}
	}

	//Make sure a node was found, if not return first node
	if ( root.is_null() )
		return blocks[0];

	//Move up the chain to the root node
	while ( root->GetParent().is_null() != true ) {
		root = root->GetParent();
	}

	return root;
}

unsigned int CheckNifHeader( string const & file_name ) {
	//--Open File--//
	ifstream in( file_name.c_str(), ifstream::binary );

	//--Read Header--//
	char header_string[64];
	in.getline( header_string, 64 );
	string headerstr(header_string);

	// make sure this is a NIF file
	if ( ( headerstr.substr(0, 22) != "NetImmerse File Format" )
	&& ( headerstr.substr(0, 20) != "Gamebryo File Format" ) )
		return VER_INVALID;

	// supported versions
	if ( headerstr == "NetImmerse File Format, Version 4.0.0.2" ) return VER_4_0_0_2;
	if ( headerstr == "NetImmerse File Format, Version 4.1.0.12" ) return VER_4_1_0_12;
	if ( headerstr == "NetImmerse File Format, Version 4.2.0.2" ) return VER_4_2_0_2;
	if ( headerstr == "NetImmerse File Format, Version 4.2.1.0" ) return VER_4_2_1_0;
	if ( headerstr == "NetImmerse File Format, Version 4.2.2.0" ) return VER_4_2_2_0;
	if ( headerstr == "NetImmerse File Format, Version 10.0.1.0" ) return VER_10_0_1_0;
	if ( headerstr == "Gamebryo File Format, Version 10.1.0.0" ) return VER_10_1_0_0;
	if ( headerstr == "Gamebryo File Format, Version 10.2.0.0" ) return VER_10_2_0_0;
	if ( headerstr == "Gamebryo File Format, Version 20.0.0.4" ) return VER_20_0_0_4;
	if ( headerstr == "Gamebryo File Format, Version 20.0.0.5" ) return VER_20_0_0_5;

	// anything else: unsupported
	return VER_UNSUPPORTED;
}

//Reads the given file by file name and returns a vector of block references
vector<blk_ref> ReadNifList( string const & file_name ) {

	//--Open File--//
	ifstream in( file_name.c_str(), ifstream::binary );

	return ReadNifList( in );
}

//Reads the given input stream and returns a vector of block references
vector<blk_ref> ReadNifList( istream & in ) {

	//--Read Header--//
	char header_string[256];
	in.getline( header_string, 256 );
	string headerstr(header_string);

	// make sure this is a NIF file
	if ( ( headerstr.substr(0, 22) != "NetImmerse File Format" )
	&& ( headerstr.substr(0, 20) != "Gamebryo File Format" ) )
		throw runtime_error("Not a NIF file.");

	// detect old versions
	if ( ( headerstr == "NetImmerse File Format, Version 3.1" )
	|| ( headerstr == "NetImmerse File Format, Version 3.03" )
	|| ( headerstr == "NetImmerse File Format, Version 3.0" )
	|| ( headerstr == "NetImmerse File Format, Version 2.3" ) )
		throw runtime_error("Unsupported: " + headerstr);

	uint version = ReadUInt( in );

	//There is an unknown Byte here from version 172.16.17.32 on
	byte unknownByte;
	if ( version >= VER_20_0_0_4 ) {
		unknownByte = ReadByte( in );
	}

	//There is an Unknown Int here from version 10.1.0.0 on
	uint unknownInt1;
	if ( version >= VER_10_1_0_0 ) {
		unknownInt1 = ReadUInt( in );
	}

	uint numBlocks = ReadUInt( in );

	vector<string> blockTypes;
	vector<short> blockTypeIndex;<commit_msg>Added support for the 20.0.0.5 header.<commit_after>/* Copyright (c) 2005, NIF File Format Library and Tools
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above
     copyright notice, this list of conditions and the following
     disclaimer in the documentation and/or other materials provided
     with the distribution.

   * Neither the name of the NIF File Format Library and Tools
     project nor the names of its contributors may be used to endorse
     or promote products derived from this software without specific
     prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */

#include "niflib.h"
#include "NIF_Blocks.h"
#include "nif_attrs.h"
#include "kfm.h"
#include <exception>
#include <stdexcept>
using namespace std;

bool verbose = false;

//Stores the mapping between block names and factory function pointers to create them
typedef IBlock * (*blk_factory_func)();
bool global_block_map_init = false;
map<string, blk_factory_func> global_block_map;

//Temporary Global to test reference counting
unsigned int blocks_in_memory = 0;

//Utility Functions
void ReorderNifTree( vector<blk_ref> & blk_list, vector<string> & blk_types, blk_ref const & block );
void BuildUpBindPositions( blk_ref const & block );
blk_ref FindRoot( vector<blk_ref> const & blocks );
void RegisterBlockFactories ();

//--Function Bodies--//
void SetVerboseMode( bool val ) { verbose = val; }

blk_ref CreateBlock( string block_type ) {
	
	//Initialize the global block list if it hasn't been done yet
	if ( global_block_map_init == false ) {
		RegisterBlockFactories();
		global_block_map_init = true;
	}

	IBlock * block = NULL;

	map<string, blk_factory_func>::iterator it;
	it = global_block_map.find(block_type);

	if ( it != global_block_map.end() ) {
		//Requested type has been registered
		block = it->second();
	} else {
		//An unknown type has been encountered
		return blk_ref(-1); //Return null block_ref
		//block = new UnknownBlock( block_type );
	}
	
	return blk_ref(block);
}

//Reads the given file by file name and returns a reference to the root block
blk_ref ReadNifTree( string const & file_name ) {
	//Read block list
	vector<blk_ref> blocks = ReadNifList( file_name );
	return FindRoot( blocks );
}

//Reads the given input stream and returns a reference to the root block
blk_ref ReadNifTree( istream & in ) {
	//Read block list
	vector<blk_ref> blocks = ReadNifList( in );
	return FindRoot( blocks );
}

blk_ref FindRoot( vector<blk_ref> const & blocks ) {
	//--Look for a NiNode that has no parents--//

	//Find the first Node
	blk_ref root;
	for (uint i = 0; i < blocks.size(); ++i) {
		if ( blocks[i]->QueryInterface(ID_NODE) || blocks[i]->GetBlockType() == "NiPixelData" ) {
			root = blocks[i];
			break;
		}
	}

	//Make sure a node was found, if not return first node
	if ( root.is_null() )
		return blocks[0];

	//Move up the chain to the root node
	while ( root->GetParent().is_null() != true ) {
		root = root->GetParent();
	}

	return root;
}

unsigned int CheckNifHeader( string const & file_name ) {
	//--Open File--//
	ifstream in( file_name.c_str(), ifstream::binary );

	//--Read Header--//
	char header_string[64];
	in.getline( header_string, 64 );
	string headerstr(header_string);

	// make sure this is a NIF file
	if ( ( headerstr.substr(0, 22) != "NetImmerse File Format" )
	&& ( headerstr.substr(0, 20) != "Gamebryo File Format" ) )
		return VER_INVALID;

	// supported versions
	if ( headerstr == "NetImmerse File Format, Version 4.0.0.2" ) return VER_4_0_0_2;
	if ( headerstr == "NetImmerse File Format, Version 4.1.0.12" ) return VER_4_1_0_12;
	if ( headerstr == "NetImmerse File Format, Version 4.2.0.2" ) return VER_4_2_0_2;
	if ( headerstr == "NetImmerse File Format, Version 4.2.1.0" ) return VER_4_2_1_0;
	if ( headerstr == "NetImmerse File Format, Version 4.2.2.0" ) return VER_4_2_2_0;
	if ( headerstr == "NetImmerse File Format, Version 10.0.1.0" ) return VER_10_0_1_0;
	if ( headerstr == "Gamebryo File Format, Version 10.1.0.0" ) return VER_10_1_0_0;
	if ( headerstr == "Gamebryo File Format, Version 10.2.0.0" ) return VER_10_2_0_0;
	if ( headerstr == "Gamebryo File Format, Version 172.16.17.32" ) return VER_20_0_0_4;
	if ( headerstr == "Gamebryo File Format, Version 172.16.17.32" ) return VER_20_0_0_5;

	// anything else: unsupported
	return VER_UNSUPPORTED;
}

//Reads the given file by file name and returns a vector of block references
vector<blk_ref> ReadNifList( string const & file_name ) {

	//--Open File--//
	ifstream in( file_name.c_str(), ifstream::binary );

	return ReadNifList( in );
}

//Reads the given input stream and returns a vector of block references
vector<blk_ref> ReadNifList( istream & in ) {

	//--Read Header--//
	char header_string[256];
	in.getline( header_string, 256 );
	string headerstr(header_string);

	// make sure this is a NIF file
	if ( ( headerstr.substr(0, 22) != "NetImmerse File Format" )
	&& ( headerstr.substr(0, 20) != "Gamebryo File Format" ) )
		throw runtime_error("Not a NIF file.");

	// detect old versions
	if ( ( headerstr == "NetImmerse File Format, Version 3.1" )
	|| ( headerstr == "NetImmerse File Format, Version 3.03" )
	|| ( headerstr == "NetImmerse File Format, Version 3.0" )
	|| ( headerstr == "NetImmerse File Format, Version 2.3" ) )
		throw runtime_error("Unsupported: " + headerstr);

	uint version = ReadUInt( in );

	//There is an unknown Byte here from version 20.0.0.4 on
	byte unknownByte;
	if ( version >= VER_20_0_0_4 ) {
		unknownByte = ReadByte( in );
	}

	//There is an Unknown Int here from version 10.1.0.0 on
	uint unknownInt1 = 0;
	if ( version >= VER_10_1_0_0 ) {
		unknownInt1 = ReadUInt( in );
	}

	uint numBlocks = ReadUInt( in );

	if ( unknownInt1 != 0 ) {
		uint len;
		ReadUInt( in );
		len = ReadByte( in );
		for (int i = 0; i < len; i++) ReadByte( in );
		len = ReadByte( in );
		for (int i = 0; i < len; i++) ReadByte( in );
		len = ReadByte( in );
		for (int i = 0; i < len; i++) ReadByte( in );
	}
	
	vector<string> blockTypes;
	vector<short> blockTypeIndex;
{'fraction_non_alphanumeric': 0.10524026962383126, 'fraction_numerical': 0.023845763571790968, 'mean_word_length': 3.981227436823105, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 25, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6830071', 'n_tokens_mistral': 4780, 'n_tokens_neox': 4431, 'n_words': 1612}