- beginning of BVH loader, to continue working at home. Not usable, yet.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@177 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
ulfjorensen 2008-10-15 16:12:18 +00:00
parent 1db46c242f
commit c128705de9
6 changed files with 496 additions and 26 deletions

314
code/BVHLoader.cpp 100644
View File

@ -0,0 +1,314 @@
/** Implementation of the BVH loader */
/*
---------------------------------------------------------------------------
Open Asset Import Library (ASSIMP)
---------------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software 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 ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
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 "AssimpPCH.h"
#include "BVHLoader.h"
#include "fast_atof.h"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
BVHLoader::BVHLoader()
{
}
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
BVHLoader::~BVHLoader()
{
}
// ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file.
bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler) const
{
// check file extension
std::string::size_type pos = pFile.find_last_of('.');
// no file extension - can't read
if( pos == std::string::npos)
return false;
std::string extension = pFile.substr( pos);
for( std::string::iterator it = extension.begin(); it != extension.end(); ++it)
*it = tolower( *it);
if( extension == ".bvh")
return true;
return false;
}
// ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure.
void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
{
mFileName = pFile;
// read file into memory
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
if( file.get() == NULL)
throw new ImportErrorException( "Failed to open file " + pFile + ".");
size_t fileSize = file->FileSize();
if( fileSize == 0)
throw new ImportErrorException( "File is too small.");
mBuffer.resize( fileSize);
file->Read( &mBuffer.front(), 1, fileSize);
// start reading
mReader = mBuffer.begin();
mLine = 1;
ReadStructure( pScene);
}
// ------------------------------------------------------------------------------------------------
// Reads the file
void BVHLoader::ReadStructure( aiScene* pScene)
{
// first comes hierarchy
std::string header = GetNextToken();
if( header != "HIERARCHY")
ThrowException( "Expected header string \"HIERARCHY\".");
ReadHierarchy( pScene);
// then comes the motion data
std::string motion = GetNextToken();
if( motion != "MOTION")
ThrowException( "Expected beginning of motion data \"MOTION\".");
ReadMotion( pScene);
}
// ------------------------------------------------------------------------------------------------
// Reads the hierarchy
void BVHLoader::ReadHierarchy( aiScene* pScene)
{
std::string root = GetNextToken();
if( root != "ROOT")
ThrowException( "Expected root node \"ROOT\".");
// Go read the hierarchy from here
pScene->mRootNode = ReadNode();
}
// ------------------------------------------------------------------------------------------------
// Reads a node and recursively its childs and returns the created node;
aiNode* BVHLoader::ReadNode()
{
// first token is name
std::string nodeName = GetNextToken();
if( nodeName.empty() || nodeName == "{")
ThrowException( boost::str( boost::format( "Expected node name, but found \"%s\".") % nodeName));
// HACK: (thom) end nodes are called "End Site". If the name of the node is "Site", we know it's going to be an end node
if( nodeName == "Site")
nodeName = "End Site";
// then an opening brace should follow
std::string openBrace = GetNextToken();
if( openBrace != "{")
ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace));
// Create a node
aiNode* node = new aiNode( nodeName);
std::vector<aiNode*> childNodes;
// now read the node's contents
while( 1)
{
std::string token = GetNextToken();
// node offset to parent node
if( token == "OFFSET")
ReadNodeOffset( node);
else if( token == "CHANNELS")
ReadNodeChannels( node);
else if( token == "JOINT")
{
// child node follows
aiNode* child = ReadNode();
childNodes.push_back( child);
} else
if( token == "End")
{
// HACK: (thom) end child node follows. Full token is "End Site", then no name, then a node.
// But I don't want to write another function for this, so I simply leave the "Site" for ReadNode() as a node name
aiNode* child = ReadNode();
childNodes.push_back( child);
} else
if( token == "}")
{
// we're done with that part of the hierarchy
break;
} else
{
// everything else is a parse error
ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token));
}
}
// add the child nodes if there are any
if( childNodes.size() > 0)
{
node->mNumChildren = childNodes.size();
node->mChildren = new aiNode*[node->mNumChildren];
std::copy( childNodes.begin(), childNodes.end(), node->mChildren);
}
// and return the sub-hierarchy we built here
return node;
}
// ------------------------------------------------------------------------------------------------
// Reads a node offset for the given node
void BVHLoader::ReadNodeOffset( aiNode* pNode)
{
// Offset consists of three floats to read
aiVector3D offset;
offset.x = GetNextTokenAsFloat();
offset.y = GetNextTokenAsFloat();
offset.z = GetNextTokenAsFloat();
// build a transformation matrix from it
pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y,
0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f);
}
// ------------------------------------------------------------------------------------------------
// Reads the animation channels for the given node
void BVHLoader::ReadNodeChannels( aiNode* pNode)
{
// number of channels. Use the float reader because we're lazy
float numChannelsFloat = GetNextTokenAsFloat();
unsigned int numChannels = (unsigned int) numChannelsFloat;
// TODO: (thom) proper channel parsing. For the moment I just skip the number of tokens
for( unsigned int a = 0; a < numChannels; a++)
GetNextToken();
}
// ------------------------------------------------------------------------------------------------
// Reads the motion data
void BVHLoader::ReadMotion( aiScene* pScene)
{
// Read number of frames
std::string tokenFrames = GetNextToken();
if( tokenFrames != "Frames:")
ThrowException( boost::str( boost::format( "Expected frame count \"Frames:\", but found \"%s\".") % tokenFrames));
float numFramesFloat = GetNextTokenAsFloat();
unsigned int numFrames = (unsigned int) numFramesFloat;
// Read frame duration
std::string tokenDuration1 = GetNextToken();
std::string tokenDuration2 = GetNextToken();
if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
ThrowException( boost::str( boost::format( "Expected frame duration \"Frame Time:\", but found \"%s %s\".") % tokenDuration1 % tokenDuration2));
float frameDuration = GetNextTokenAsFloat();
// resize value array accordingly
// ************* Continue here ********
//mMotionValues.resize( boost::extents[numFrames][numChannels]);
}
// ------------------------------------------------------------------------------------------------
// Retrieves the next token
std::string BVHLoader::GetNextToken()
{
// skip any preceeding whitespace
while( mReader != mBuffer.end())
{
if( !isspace( *mReader))
break;
// count lines
if( *mReader == '\n')
mLine++;
++mReader;
}
// collect all chars till the next whitespace. BVH is easy in respect to that.
std::string token;
while( mReader != mBuffer.end())
{
if( isspace( *mReader))
break;
token.push_back( *mReader);
++mReader;
// little extra logic to make sure braces are counted correctly
if( token == "{" || token == "}")
break;
}
// empty token means end of file, which is just fine
return token;
}
// ------------------------------------------------------------------------------------------------
// Reads the next token as a float
float BVHLoader::GetNextTokenAsFloat()
{
std::string token = GetNextToken();
if( token.empty())
ThrowException( "Unexpected end of file while trying to read a float");
// check if the float is valid by testing if the atof() function consumed every char of the token
const char* ctoken = token.c_str();
float result = 0.0f;
ctoken = fast_atof_move( ctoken, result);
if( ctoken != token.c_str() + token.length())
ThrowException( boost::str( boost::format( "Expected a floating point number, but found \"%s\".") % token));
return result;
}
// ------------------------------------------------------------------------------------------------
// Aborts the file reading with an exception
void BVHLoader::ThrowException( const std::string& pError)
{
throw new ImportErrorException( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError));
}

133
code/BVHLoader.h 100644
View File

@ -0,0 +1,133 @@
/** Defines the BHV motion capturing loader class */
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------
Copyright (c) 2006-2008, ASSIMP Development Team
All rights reserved.
Redistribution and use of this software 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 ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
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.
----------------------------------------------------------------------
*/
#ifndef AI_BVHLOADER_H_INC
#define AI_BVHLOADER_H_INC
#include "BaseImporter.h"
#include <boost/multi_array.hpp>
namespace Assimp
{
/** Loader class to read Motion Capturing data from a .bvh file. This format only contains a
* hierarchy of joints and a series of keyframes for the hierarchy. It contains no actual mesh data,
* but we generate a dummy mesh inside the loader just to be able to see something.
*/
class BVHLoader : public BaseImporter
{
friend class Importer;
protected:
/** Constructor to be privately used by Importer */
BVHLoader();
/** Destructor, private as well */
~BVHLoader();
public:
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler) const;
protected:
/** Called by Importer::GetExtensionList() for each loaded importer.
* See BaseImporter::GetExtensionList() for details
*/
void GetExtensionList( std::string& append)
{
append.append("*.bvh");
}
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details
*/
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
protected:
/** Reads the file */
void ReadStructure( aiScene* pScene);
/** Reads the hierarchy */
void ReadHierarchy( aiScene* pScene);
/** Reads a node and recursively its childs and returns the created node. */
aiNode* ReadNode();
/** Reads a node offset for the given node */
void ReadNodeOffset( aiNode* pNode);
/** Reads the animation channels for the given node */
void ReadNodeChannels( aiNode* pNode);
/** Reads the motion data */
void ReadMotion( aiScene* pScene);
/** Retrieves the next token */
std::string GetNextToken();
/** Reads the next token as a float */
float GetNextTokenAsFloat();
/** Aborts the file reading with an exception */
void ThrowException( const std::string& pError);
protected:
/** Filename, for a verbose error message */
std::string mFileName;
/** Buffer to hold the loaded file */
std::vector<char> mBuffer;
/** Next char to read from the buffer */
std::vector<char>::const_iterator mReader;
/** Current line, for error messages */
unsigned int mLine;
/** motion values per frame */
boost::multi_array<float, 2> mMotionValues;
};
} // end of namespace Assimp
#endif // AI_BVHLOADER_H_INC

View File

@ -113,6 +113,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_BUILD_NO_AC_IMPORTER
# include "ACLoader.h"
#endif
#ifndef AI_BUILD_NO_BVH_IMPORTER
# include "BVHLoader.h"
#endif
// PostProcess-Steps
@ -254,6 +257,9 @@ Importer::Importer() :
#if (!defined AI_BUILD_NO_AC_IMPORTER)
mImporter.push_back( new AC3DImporter());
#endif
#if (!defined AI_BUILD_NO_BVH_IMPORTER)
mImporter.push_back( new BVHLoader());
#endif
// add an instance of each post processing step here in the order
// of sequence it is executed. steps that are added here are not validated -

View File

@ -12,18 +12,18 @@ 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.
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.
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 ASSIMP team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the ASSIMP Development Team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@ -103,9 +103,9 @@ void XFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene, I
// and create the proper return structures out of it
CreateDataRepresentationFromImport( pScene, parser.GetImportedData());
// if nothing came from it, report it as error
if( !pScene->mRootNode)
throw new ImportErrorException( "XFile is ill-formatted - no content imported.");
// if nothing came from it, report it as error
if( !pScene->mRootNode)
throw new ImportErrorException( "XFile is ill-formatted - no content imported.");
}
// ------------------------------------------------------------------------------------------------
@ -139,8 +139,8 @@ void XFileImporter::CreateDataRepresentationFromImport( aiScene* pScene, const X
}
// convert the root node's transformation to OGL coords
if( pScene->mRootNode)
ConvertToLHProcess::ConvertToOGL( pScene->mRootNode->mTransformation);
if( pScene->mRootNode)
ConvertToLHProcess::ConvertToOGL( pScene->mRootNode->mTransformation);
// finally: create a dummy material if not material was imported
if( pScene->mNumMaterials == 0)
@ -180,7 +180,7 @@ aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFil
memcpy( node->mName.data, pNode->mName.c_str(), pNode->mName.length());
node->mName.data[node->mName.length] = 0;
node->mTransformation = pNode->mTrafoMatrix;
// convert meshes from the source node
CreateMeshes( pScene, node, pNode->mMeshes);
@ -323,7 +323,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
for( unsigned int e = 0; e < AI_MAX_NUMBER_OF_COLOR_SETS; e++)
if( mesh->HasVertexColors( e))
mesh->mColors[e][newIndex] = sourceMesh->mColors[e][pf.mIndices[d]];
newIndex++;
}
}
@ -423,7 +423,7 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
const XFile::AnimBone* bone = anim->mAnims[b];
aiNodeAnim* nbone = new aiNodeAnim;
nbone->mNodeName.Set( bone->mBoneName);
nanim->mChannels[b] = nbone;
nanim->mChannels[b] = nbone;
// apply the LH->RH conversion if the animation affects the root bone
bool isRootAnim = (bone->mBoneName == pScene->mRootNode->mName.data);
@ -650,7 +650,7 @@ void XFileImporter::ConvertMaterials( aiScene* pScene, const std::vector<XFile::
::sprintf(key,AI_MATKEY_TEXTURE_EMISSIVE_ "[%i]",iEM++);
} else
{
// assume it is a diffuse texture
// assume it is a diffuse texture
::sprintf(key,AI_MATKEY_TEXTURE_DIFFUSE_ "[%i]",iDM++);
}

View File

@ -2,13 +2,13 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AssimpView", "assimp_view.vcproj", "{B17B959B-BB8A-4596-AF0F-A8C8DBBC3C5E}"
ProjectSection(ProjectDependencies) = postProject
{5691E159-2D9B-407F-971F-EA5C592DC524} = {5691E159-2D9B-407F-971F-EA5C592DC524}
EndProjectSection
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
ProjectSection(ProjectDependencies) = postProject
{5691E159-2D9B-407F-971F-EA5C592DC524} = {5691E159-2D9B-407F-971F-EA5C592DC524}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Assimp", "assimp.vcproj", "{5691E159-2D9B-407F-971F-EA5C592DC524}"
ProjectSection(WebsiteProperties) = preProject
@ -17,15 +17,15 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Assimp", "assimp.vcproj", "
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTest", "UnitTest.vcproj", "{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}"
ProjectSection(ProjectDependencies) = postProject
{5691E159-2D9B-407F-971F-EA5C592DC524} = {5691E159-2D9B-407F-971F-EA5C592DC524}
EndProjectSection
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
EndProjectSection
ProjectSection(ProjectDependencies) = postProject
{5691E159-2D9B-407F-971F-EA5C592DC524} = {5691E159-2D9B-407F-971F-EA5C592DC524}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jAssimp", "jAssimp.vcproj", "{FE78BFBA-4BA5-457D-8602-B800D498102D}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jAssimp_NOT_WORKING", "jAssimp.vcproj", "{FE78BFBA-4BA5-457D-8602-B800D498102D}"
ProjectSection(WebsiteProperties) = preProject
Debug.AspNetCompiler.Debug = "True"
Release.AspNetCompiler.Debug = "False"
@ -80,7 +80,6 @@ Global
{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug_DLL|x64.ActiveCfg = Debug_DLL|x64
{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug_DLL|x64.Build.0 = Debug_DLL|x64
{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug|Win32.ActiveCfg = Debug|Win32
{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug|Win32.Build.0 = Debug|Win32
{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug|x64.ActiveCfg = Debug|x64
{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Debug|x64.Build.0 = Debug|x64
{9B9D1C90-8A03-409A-B547-AE7B48B90F1A}.Release_DLL|Win32.ActiveCfg = Release_DLL|Win32

View File

@ -47,6 +47,8 @@
SmallerTypeCheck="true"
RuntimeLibrary="1"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="AssimpPCH.h"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
@ -305,6 +307,8 @@
RuntimeLibrary="2"
BufferSecurityCheck="false"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="AssimpPCH.h"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
/>
@ -455,6 +459,8 @@
SmallerTypeCheck="true"
RuntimeLibrary="3"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="AssimpPCH.h"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
@ -1324,6 +1330,18 @@
>
</File>
</Filter>
<Filter
Name="BVH"
>
<File
RelativePath="..\..\code\BVHLoader.cpp"
>
</File>
<File
RelativePath="..\..\code\BVHLoader.h"
>
</File>
</Filter>
</Filter>
<Filter
Name="PostProcess"
@ -1484,7 +1502,7 @@
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration