|
- /*
- Open Asset Import Library (assimp)
- ----------------------------------------------------------------------
-
- Copyright (c) 2006-2008, assimp 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 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/assimp/IOSystem.hpp"
- #include "fast_atof.h"
- #include "ParsingUtils.h"
- namespace Assimp {
-
- inline bool IsHex(char s) {
- return (s>='0' && s<='9') || (s>='a' && s<='f') || (s>='A' && s<='F');
- }
-
- // ---------------------------------------------------------------------------
- /** File system filter
- */
- class FileSystemFilter : public IOSystem
- {
- public:
- /** Constructor. */
- FileSystemFilter(const std::string& file, IOSystem* old)
- : wrapped (old)
- , src_file (file)
- , sep(wrapped->getOsSeparator())
- {
- 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 = ".";
- base += getOsSeparator();
- }
- else if ((s = *(base.end()-1)) != '\\' && s != '/') {
- base += getOsSeparator();
- }
-
- 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 sep;
- }
-
- // -------------------------------------------------------------------
- /** Open a new file with a given path. */
- IOStream* Open( const char* pFile, const char* pMode = "rb")
- {
- ai_assert(pFile);
- ai_assert(pMode);
-
- // First try the unchanged path
- IOStream* s = wrapped->Open(pFile,pMode);
-
- if (!s) {
- std::string tmp = pFile;
-
- // Try to convert between absolute and relative paths
- BuildPath(tmp);
- s = wrapped->Open(tmp,pMode);
-
- if (!s) {
- // Finally, look for typical issues with paths
- // and try to correct them. This is our last
- // resort.
- tmp = pFile;
- Cleanup(tmp);
- BuildPath(tmp);
- s = wrapped->Open(tmp,pMode);
- }
- }
-
- return s;
- }
-
- // -------------------------------------------------------------------
- /** 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:
-
- // -------------------------------------------------------------------
- /** 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)) {
- return;
- }
-
- // Determine whether this is a relative path (Windows-specific - most assets are packaged on Windows).
- if (in[1] != ':') {
-
- // append base path and try
- const std::string tmp = base + in;
- if (wrapped->Exists(tmp)) {
- in = tmp;
- return;
- }
- }
-
- // Chop of the file name and look in the model directory, if
- // this fails try all sub paths of the given path, i.e.
- // if the given path is foo/bar/something.lwo, try
- // <base>/something.lwo
- // <base>/bar/something.lwo
- // <base>/foo/bar/something.lwo
- std::string::size_type pos = in.rfind('/');
- if (std::string::npos == pos) {
- pos = in.rfind('\\');
- }
-
- if (std::string::npos != pos) {
- std::string tmp;
- std::string::size_type last_dirsep = std::string::npos;
-
- while(true) {
- tmp = base;
- tmp += sep;
-
- std::string::size_type dirsep = in.rfind('/', last_dirsep);
- if (std::string::npos == dirsep) {
- dirsep = in.rfind('\\', last_dirsep);
- }
-
- if (std::string::npos == dirsep || dirsep == 0) {
- // we did try this already.
- break;
- }
-
- last_dirsep = dirsep-1;
-
- tmp += in.substr(dirsep+1, in.length()-pos);
- if (wrapped->Exists(tmp)) {
- in = tmp;
- return;
- }
- }
- }
-
- // hopefully the underlying file system has another few tricks to access this file ...
- }
-
- // -------------------------------------------------------------------
- /** Cleanup the given path
- */
- void Cleanup (std::string& in) const
- {
- char last = 0;
- if(in.empty()) {
- return;
- }
-
- // 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) {
- // Exclude :// and \\, which remain untouched.
- // https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
- if ( !strncmp(&*it, "://", 3 )) {
- it += 3;
- continue;
- }
- if (it == in.begin() && !strncmp(&*it, "\\\\", 2)) {
- it += 2;
- continue;
- }
-
- // Cleanup path delimiters
- 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 in URIs
- if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
- *it = HexOctetToDecimal(&*it);
- it = in.erase(it+1,it+2);
- --it;
- }
- }
-
- last = *it;
- }
- }
-
- private:
- IOSystem* wrapped;
- std::string src_file, base;
- char sep;
- };
-
- } //!ns Assimp
-
- #endif //AI_DEFAULTIOSYSTEM_H_INC
|