Adding a file system filter layer to correct invalid paths automatically.

git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@381 67173fc5-114c-0410-ac8e-9d2fd5bffc1f
pull/1/head
aramis_acg 2009-04-10 21:59:22 +00:00
parent fb33a6bfc4
commit a3b32f306c
11 changed files with 388 additions and 207 deletions

View File

@ -45,10 +45,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "AssimpPCH.h"
#include "BaseImporter.h"
#include "FileSystemFilter.h"
using namespace Assimp;
// ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer
BaseImporter::BaseImporter()
@ -67,13 +67,16 @@ BaseImporter::~BaseImporter()
// Imports the given file and returns the imported data.
aiScene* BaseImporter::ReadFile( const std::string& pFile, IOSystem* pIOHandler)
{
// Construct a file system filter to improve our success ratio reading external files
FileSystemFilter filter(pFile,pIOHandler);
// create a scene object to hold the data
aiScene* scene = new aiScene();
// dispatch importing
try
{
InternReadFile( pFile, scene, pIOHandler);
InternReadFile( pFile, scene, &filter);
} catch( ImportErrorException* exception)
{
// extract error description
@ -291,47 +294,24 @@ BatchLoader::BatchLoader(IOSystem* pIO)
data = new BatchData();
data->pIOSystem = pIO;
data->pImporter = new Importer();
data->pImporter->SetIOHandler(data->pIOSystem);
}
// ------------------------------------------------------------------------------------------------
BatchLoader::~BatchLoader()
{
// delete all scenes wthat have not been polled by the user
for (std::list<LoadRequest>::iterator it = data->requests.begin();
it != data->requests.end(); ++it)
{
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
delete (*it).scene;
}
data->pImporter->SetIOHandler(NULL); /* get pointer back into our posession */
delete data->pImporter;
delete data;
}
// ------------------------------------------------------------------------------------------------
void BatchLoader::SetBasePath (const std::string& pBase)
{
data->pathBase = pBase;
// file name? we just need the directory
std::string::size_type ss,ss2;
if (std::string::npos != (ss = data->pathBase.find_first_of('.')))
{
if (std::string::npos != (ss2 = data->pathBase.find_last_of("\\/")))
{
if (ss > ss2)
data->pathBase.erase(ss2,data->pathBase.length()-ss2);
}
else {
data->pathBase = "";
return;
}
}
// make sure the directory is terminated properly
char s;
if ((s = *(data->pathBase.end()-1)) != '\\' && s != '/')
data->pathBase.append("\\");
}
// ------------------------------------------------------------------------------------------------
unsigned int BatchLoader::AddLoadRequest (const std::string& file,
@ -339,23 +319,13 @@ unsigned int BatchLoader::AddLoadRequest (const std::string& file,
{
ai_assert(!file.empty());
// no threaded implementation for the moment
std::string real;
// build a full path if this is a relative path and
// we have a new base directory given
if (file.length() > 2 && file[1] != ':' && data->pathBase.length()) {
real = data->pathBase + file;
}
else real = file;
// check whether we have this loading request already
std::list<LoadRequest>::iterator it;
for (it = data->requests.begin();it != data->requests.end(); ++it)
{
for (it = data->requests.begin();it != data->requests.end(); ++it) {
// Call IOSystem's path comparison function here
if (data->pIOSystem->ComparePaths((*it).file,real))
{
if (data->pIOSystem->ComparePaths((*it).file,file)) {
if (map) {
if (!((*it).map == *map))
continue;
@ -369,20 +339,19 @@ unsigned int BatchLoader::AddLoadRequest (const std::string& file,
}
// no, we don't have it. So add it to the queue ...
data->requests.push_back(LoadRequest(real,steps,map,data->next_id));
data->requests.push_back(LoadRequest(file,steps,map,data->next_id));
return data->next_id++;
}
// ------------------------------------------------------------------------------------------------
aiScene* BatchLoader::GetImport (unsigned int which)
{
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it)
{
if ((*it).id == which && (*it).loaded)
{
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
if ((*it).id == which && (*it).loaded) {
aiScene* sc = (*it).scene;
if (!(--(*it).refCnt))
{
if (!(--(*it).refCnt)) {
data->requests.erase(it);
}
return sc;
@ -395,9 +364,7 @@ aiScene* BatchLoader::GetImport (unsigned int which)
void BatchLoader::LoadAll()
{
// no threaded implementation for the moment
for (std::list<LoadRequest>::iterator it = data->requests.begin();
it != data->requests.end(); ++it)
{
for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) {
// force validation in debug builds
unsigned int pp = (*it).flags;
#ifdef _DEBUG

View File

@ -356,17 +356,6 @@ public:
~BatchLoader();
/** Sets the base path to be used for all subsequent load
* calls. This is the working directory of Assimp.
*
* Every (inplicit) occurence of '.\' will be replaced with it.
*
* @param pBase Base path. This *may* also be the path to
* a file (the directory of the file is taken then, of course)
*/
void SetBasePath (const std::string& pBase);
/** Add a new file to the list of files to be loaded.
*
* @param file File to be loaded

View File

@ -0,0 +1,220 @@
/*
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.
----------------------------------------------------------------------
*/
/** @file FileSystemFilter.h
* Implements a filter system to filter calls to Exists() and Open()
* in order to improve the sucess rate of file opening ...
*/
#ifndef AI_FILESYSTEMFILTER_H_INC
#define AI_FILESYSTEMFILTER_H_INC
#include "../include/IOSystem.h"
#include "fast_atof.h"
#include "ParsingUtils.h"
namespace Assimp {
// ---------------------------------------------------------------------------
/** File system filter
*/
class FileSystemFilter : public IOSystem
{
public:
/** Constructor. */
FileSystemFilter(const std::string& file, IOSystem* old)
: wrapped (old)
, src_file (file)
{
ai_assert(NULL != wrapped);
// Determine base directory
base = src_file;
std::string::size_type ss2;
if (std::string::npos != (ss2 = base.find_last_of("\\/"))) {
base.erase(ss2,base.length()-ss2);
}
else {
base = "";
return;
}
// make sure the directory is terminated properly
char s;
if (base.length() == 0) {
base = ".\\";
}
else if ((s = *(base.end()-1)) != '\\' && s != '/')
base.append("\\");
DefaultLogger::get()->info("Import root directory is \'" + base + "\'");
}
/** Destructor. */
~FileSystemFilter()
{
// haha
}
// -------------------------------------------------------------------
/** Tests for the existence of a file at the given path. */
bool Exists( const char* pFile) const
{
std::string tmp = pFile;
// Currently this IOSystem is also used to open THE ONE FILE.
if (tmp != src_file) {
BuildPath(tmp);
Cleanup(tmp);
}
return wrapped->Exists(tmp);
}
// -------------------------------------------------------------------
/** Returns the directory separator. */
char getOsSeparator() const
{
return wrapped->getOsSeparator();
}
// -------------------------------------------------------------------
/** Open a new file with a given path. */
IOStream* Open( const char* pFile, const char* pMode = "rb")
{
std::string tmp = pFile;
// Currently this IOSystem is also used to open THE ONE FILE.
if (tmp != src_file) {
BuildPath(tmp);
Cleanup(tmp);
}
return wrapped->Open(tmp,pMode);
}
// -------------------------------------------------------------------
/** Closes the given file and releases all resources associated with it. */
void Close( IOStream* pFile)
{
return wrapped->Close(pFile);
}
// -------------------------------------------------------------------
/** Compare two paths */
bool ComparePaths (const char* one, const char* second) const
{
return wrapped->ComparePaths (one,second);
}
private:
IOSystem* wrapped;
std::string src_file, base;
// -------------------------------------------------------------------
/** Build a valid path from a given relative or absolute path.
*/
void BuildPath (std::string& in) const
{
// if we can already access the file, great.
if (in.length() < 3 || wrapped->Exists(in.c_str())) {
return;
}
// Determine whether this is a relative path.
if (in[1] != ':') {
// append base path and try
in = base + in;
if (wrapped->Exists(in.c_str())) {
return;
}
}
// hopefully the underyling file system has another few tricks to access this file ...
}
// -------------------------------------------------------------------
/** Cleanup the given path
*/
void Cleanup (std::string& in) const
{
char last = 0;
// Remove a very common issue when we're parsing file names: spaces at the
// beginning of the path.
std::string::iterator it = in.begin();
while (IsSpaceOrNewLine( *it ))++it;
if (it != in.begin())
in.erase(in.begin(),it+1);
const char sep = getOsSeparator();
for (it = in.begin(); it != in.end(); ++it) {
// Both Windows and Linux accept both separators, but to avoid conflicts
// or mixed seperators in a single path we're cleaning up.
if (*it == '/' || (*it) == '\\') {
*it = sep;
// And we're removing double delimiters, frequent issue with
// incorrectly composited paths ...
if (last == *it) {
it = in.erase(it);
--it;
}
}
else if (*it == '%' && in.end() - it > 2) {
// Hex sequence, common _artifact_ in URIs
uint32_t tmp;
if( 0xffffffff != (tmp = HexOctetToDecimal(&*it))) {
*it = (char)tmp;
it = in.erase(it+1,it+2);
--it;
}
}
last = *it;
}
}
};
} //!ns Assimp
#endif //AI_DEFAULTIOSYSTEM_H_INC

View File

@ -906,7 +906,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
// Batch loader used to load external models
BatchLoader batch(pIOHandler);
batch.SetBasePath(pFile);
// batch.SetBasePath(pFile);
cameras.reserve(5);
lights.reserve(5);

View File

@ -559,7 +559,8 @@ void Importer::SetIOHandler( IOSystem* pIOHandler)
// If the new handler is zero, allocate a default IO implementation.
if (!pIOHandler)
{
delete mIOHandler;
// Release pointer in the possession of the caller
// delete mIOHandler;
mIOHandler = new DefaultIOSystem();
mIsDefaultHandler = true;
}

View File

@ -318,9 +318,9 @@ void AnimResolver::DoInterpolation2(std::vector<LWO::Key>::const_iterator beg,
void AnimResolver::SubsampleAnimTrack(std::vector<aiVectorKey>& out,
double time,double sample_delta)
{
ai_assert(!out.empty() && sample_delta);
ai_assert(out.empty() && sample_delta);
const double time_start = out.back().mTime;
//const double time_start = out.back().mTime;
// for ()
}
@ -512,8 +512,7 @@ void AnimResolver::ExtractAnimChannel(aiNodeAnim** out, unsigned int flags /*= 0
return;
}
// We won't spawn an animation channel if we don't have at least one
// envelope with more than one keyframe defined.
// We won't spawn an animation channel if we don't have at least one envelope with more than one keyframe defined.
const bool trans = (trans_x && trans_x->keys.size() > 1 || trans_y && trans_y->keys.size() > 1 || trans_z && trans_z->keys.size() > 1);
const bool rotat = (rotat_x && rotat_x->keys.size() > 1 || rotat_y && rotat_y->keys.size() > 1 || rotat_z && rotat_z->keys.size() > 1);
const bool scale = (scale_x && scale_x->keys.size() > 1 || scale_y && scale_y->keys.size() > 1 || scale_z && scale_z->keys.size() > 1);

View File

@ -312,10 +312,10 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
// Setup a very cryptic name for the node, we want the user to be happy
SetupNodeName(nd,src);
// If this is an object from an external file - get the scene
// and setup proper attachment tags
// If this is an object from an external file - get the scene and setup proper attachment tags
aiScene* obj = NULL;
if (src.type == LWS::NodeDesc::OBJECT && src.path.length() ) {
aiScene* obj = batch.GetImport(src.id);
obj = batch.GetImport(src.id);
if (!obj) {
DefaultLogger::get()->error("LWS: Failed to read external file " + src.path);
}
@ -370,7 +370,7 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
// .. and construct animation channels
aiNodeAnim* anim = NULL;
#if 1 /* not yet */
if (first != last) {
resolver.SetAnimationRange(first,last);
resolver.ExtractAnimChannel(&anim,AI_LWO_ANIM_FLAG_SAMPLE_ANIMS|AI_LWO_ANIM_FLAG_START_AT_ZERO);
@ -379,7 +379,6 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
animOut.push_back(anim);
}
}
#endif
// process pivot point, if any
if (src.pivotPos != aiVector3D()) {
@ -397,7 +396,7 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
// Maybe the final optimization here will be done during postprocessing.
aiNode* pivot = new aiNode();
pivot->mName.Set("$Pivot");
pivot->mName.length = sprintf( pivot->mName.data, "$Pivot_%s",nd->mName.data);
pivot->mTransformation = tmp;
pivot->mChildren = new aiNode*[pivot->mNumChildren = 1];
@ -406,11 +405,11 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
pivot->mParent = nd->mParent;
nd->mParent = pivot;
// swap children ad hope the parents wont see a huge difference
// swap children and hope the parents wont see a huge difference
pivot->mParent->mChildren[pivot->mParent->mNumChildren-1] = pivot;
}
else {
nd->mTransformation = tmp * nd->mTransformation;
nd->mTransformation = tmp*nd->mTransformation;
}
}
@ -484,7 +483,7 @@ void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
// Construct a Batchimporter to read more files recursively
BatchLoader batch(pIOHandler);
batch.SetBasePath(pFile);
// batch.SetBasePath(pFile);
// Construct an array to receive the flat output graph
std::list<LWS::NodeDesc> nodes;

View File

@ -78,12 +78,12 @@ public:
aiVector3D& operator *= (const aiMatrix4x4& mat);
// access a single element
inline float operator[](unsigned int i) const;
inline float& operator[](unsigned int i);
float operator[](unsigned int i) const;
float& operator[](unsigned int i);
// comparison
inline bool operator== (const aiVector3D& other) const;
inline bool operator!= (const aiVector3D& other) const;
bool operator== (const aiVector3D& other) const;
bool operator!= (const aiVector3D& other) const;
public:

View File

@ -273,9 +273,11 @@ public:
*
* The Importer takes ownership of the object and will destroy it
* afterwards. The previously assigned handler will be deleted.
* Pass NULL to take again ownership of your IOSystem and reset Assimp
* to use its default implementation.
*
* @param pIOHandler The IO handler to be used in all file accesses
* of the Importer. NULL resets it to the default handler.
* of the Importer.
*/
void SetIOHandler( IOSystem* pIOHandler);

View File

@ -7,7 +7,7 @@ rem It is included by assimp.rc.
rem -----------------------------------------------------
rem This is not very elegant, but it works.
rem ./bin shouldn't have any alocal modifications
rem ./bin shouldn't have any local modifications
cd ..\bin
svnversion > tmpfile.txt

View File

@ -1300,126 +1300,6 @@
<Filter
Name="sources"
>
<File
RelativePath="..\..\code\aiAssert.cpp"
>
</File>
<File
RelativePath="..\..\code\Assimp.cpp"
>
</File>
<File
RelativePath="..\..\code\BaseImporter.cpp"
>
</File>
<File
RelativePath="..\..\code\BaseImporter.h"
>
</File>
<File
RelativePath="..\..\code\BaseProcess.cpp"
>
</File>
<File
RelativePath="..\..\code\BaseProcess.h"
>
</File>
<File
RelativePath="..\..\code\IFF.h"
>
</File>
<File
RelativePath="..\..\code\Importer.cpp"
>
</File>
<File
RelativePath="..\..\code\MaterialSystem.cpp"
>
</File>
<File
RelativePath="..\..\code\MaterialSystem.h"
>
</File>
<File
RelativePath="..\..\code\RemoveComments.cpp"
>
</File>
<File
RelativePath="..\..\code\RemoveComments.h"
>
</File>
<File
RelativePath="..\..\code\SceneCombiner.cpp"
>
</File>
<File
RelativePath="..\..\code\SceneCombiner.h"
>
</File>
<File
RelativePath="..\..\code\ScenePreprocessor.cpp"
>
</File>
<File
RelativePath="..\..\code\ScenePreprocessor.h"
>
</File>
<File
RelativePath="..\..\code\SGSpatialSort.cpp"
>
</File>
<File
RelativePath="..\..\code\SGSpatialSort.h"
>
</File>
<File
RelativePath="..\..\code\SkeletonMeshBuilder.cpp"
>
</File>
<File
RelativePath="..\..\code\SkeletonMeshBuilder.h"
>
</File>
<File
RelativePath="..\..\code\SmoothingGroups.h"
>
</File>
<File
RelativePath="..\..\code\SmoothingGroups.inl"
>
</File>
<File
RelativePath="..\..\code\SpatialSort.cpp"
>
</File>
<File
RelativePath="..\..\code\SpatialSort.h"
>
</File>
<File
RelativePath="..\..\code\StandardShapes.cpp"
>
</File>
<File
RelativePath="..\..\code\StandardShapes.h"
>
</File>
<File
RelativePath="..\..\code\TargetAnimation.cpp"
>
</File>
<File
RelativePath="..\..\code\TargetAnimation.h"
>
</File>
<File
RelativePath="..\..\code\VertexTriangleAdjacency.cpp"
>
</File>
<File
RelativePath="..\..\code\VertexTriangleAdjacency.h"
>
</File>
<Filter
Name="extra"
>
@ -2363,14 +2243,42 @@
RelativePath="..\..\code\DefaultIOSystem.h"
>
</File>
<File
RelativePath="..\..\code\FileSystemFilter.h"
>
</File>
<File
RelativePath="..\..\code\StreamReader.h"
>
</File>
</Filter>
<Filter
Name="Util"
Name="core"
>
<File
RelativePath="..\..\code\aiAssert.cpp"
>
</File>
<File
RelativePath="..\..\code\Assimp.cpp"
>
</File>
<File
RelativePath="..\..\code\BaseImporter.cpp"
>
</File>
<File
RelativePath="..\..\code\BaseImporter.h"
>
</File>
<File
RelativePath="..\..\code\BaseProcess.cpp"
>
</File>
<File
RelativePath="..\..\code\BaseProcess.h"
>
</File>
<File
RelativePath="..\..\code\ByteSwap.h"
>
@ -2387,6 +2295,22 @@
RelativePath="..\..\code\Hash.h"
>
</File>
<File
RelativePath="..\..\code\IFF.h"
>
</File>
<File
RelativePath="..\..\code\Importer.cpp"
>
</File>
<File
RelativePath="..\..\code\MaterialSystem.cpp"
>
</File>
<File
RelativePath="..\..\code\MaterialSystem.h"
>
</File>
<File
RelativePath="..\..\code\ParsingUtils.h"
>
@ -2395,10 +2319,90 @@
RelativePath="..\..\code\qnan.h"
>
</File>
<File
RelativePath="..\..\code\RemoveComments.cpp"
>
</File>
<File
RelativePath="..\..\code\RemoveComments.h"
>
</File>
<File
RelativePath="..\..\code\SceneCombiner.cpp"
>
</File>
<File
RelativePath="..\..\code\SceneCombiner.h"
>
</File>
<File
RelativePath="..\..\code\ScenePreprocessor.cpp"
>
</File>
<File
RelativePath="..\..\code\ScenePreprocessor.h"
>
</File>
<File
RelativePath="..\..\code\SGSpatialSort.cpp"
>
</File>
<File
RelativePath="..\..\code\SGSpatialSort.h"
>
</File>
<File
RelativePath="..\..\code\SkeletonMeshBuilder.cpp"
>
</File>
<File
RelativePath="..\..\code\SkeletonMeshBuilder.h"
>
</File>
<File
RelativePath="..\..\code\SmoothingGroups.h"
>
</File>
<File
RelativePath="..\..\code\SmoothingGroups.inl"
>
</File>
<File
RelativePath="..\..\code\SpatialSort.cpp"
>
</File>
<File
RelativePath="..\..\code\SpatialSort.h"
>
</File>
<File
RelativePath="..\..\code\StandardShapes.cpp"
>
</File>
<File
RelativePath="..\..\code\StandardShapes.h"
>
</File>
<File
RelativePath="..\..\code\StringComparison.h"
>
</File>
<File
RelativePath="..\..\code\TargetAnimation.cpp"
>
</File>
<File
RelativePath="..\..\code\TargetAnimation.h"
>
</File>
<File
RelativePath="..\..\code\VertexTriangleAdjacency.cpp"
>
</File>
<File
RelativePath="..\..\code\VertexTriangleAdjacency.h"
>
</File>
</Filter>
<Filter
Name="extern"