vrshoot

annotate libs/assimp/FileSystemFilter.h @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 Open Asset Import Library (assimp)
nuclear@0 3 ----------------------------------------------------------------------
nuclear@0 4
nuclear@0 5 Copyright (c) 2006-2008, assimp team
nuclear@0 6 All rights reserved.
nuclear@0 7
nuclear@0 8 Redistribution and use of this software in source and binary forms,
nuclear@0 9 with or without modification, are permitted provided that the
nuclear@0 10 following conditions are met:
nuclear@0 11
nuclear@0 12 * Redistributions of source code must retain the above
nuclear@0 13 copyright notice, this list of conditions and the
nuclear@0 14 following disclaimer.
nuclear@0 15
nuclear@0 16 * Redistributions in binary form must reproduce the above
nuclear@0 17 copyright notice, this list of conditions and the
nuclear@0 18 following disclaimer in the documentation and/or other
nuclear@0 19 materials provided with the distribution.
nuclear@0 20
nuclear@0 21 * Neither the name of the assimp team, nor the names of its
nuclear@0 22 contributors may be used to endorse or promote products
nuclear@0 23 derived from this software without specific prior
nuclear@0 24 written permission of the assimp team.
nuclear@0 25
nuclear@0 26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 37
nuclear@0 38 ----------------------------------------------------------------------
nuclear@0 39 */
nuclear@0 40
nuclear@0 41 /** @file FileSystemFilter.h
nuclear@0 42 * Implements a filter system to filter calls to Exists() and Open()
nuclear@0 43 * in order to improve the sucess rate of file opening ...
nuclear@0 44 */
nuclear@0 45 #ifndef AI_FILESYSTEMFILTER_H_INC
nuclear@0 46 #define AI_FILESYSTEMFILTER_H_INC
nuclear@0 47
nuclear@0 48 #include "assimp/IOSystem.hpp"
nuclear@0 49 #include "fast_atof.h"
nuclear@0 50 #include "ParsingUtils.h"
nuclear@0 51 namespace Assimp {
nuclear@0 52
nuclear@0 53 inline bool IsHex(char s) {
nuclear@0 54 return (s>='0' && s<='9') || (s>='a' && s<='f') || (s>='A' && s<='F');
nuclear@0 55 }
nuclear@0 56
nuclear@0 57 // ---------------------------------------------------------------------------
nuclear@0 58 /** File system filter
nuclear@0 59 */
nuclear@0 60 class FileSystemFilter : public IOSystem
nuclear@0 61 {
nuclear@0 62 public:
nuclear@0 63 /** Constructor. */
nuclear@0 64 FileSystemFilter(const std::string& file, IOSystem* old)
nuclear@0 65 : wrapped (old)
nuclear@0 66 , src_file (file)
nuclear@0 67 , sep(wrapped->getOsSeparator())
nuclear@0 68 {
nuclear@0 69 ai_assert(NULL != wrapped);
nuclear@0 70
nuclear@0 71 // Determine base directory
nuclear@0 72 base = src_file;
nuclear@0 73 std::string::size_type ss2;
nuclear@0 74 if (std::string::npos != (ss2 = base.find_last_of("\\/"))) {
nuclear@0 75 base.erase(ss2,base.length()-ss2);
nuclear@0 76 }
nuclear@0 77 else {
nuclear@0 78 base = "";
nuclear@0 79 // return;
nuclear@0 80 }
nuclear@0 81
nuclear@0 82 // make sure the directory is terminated properly
nuclear@0 83 char s;
nuclear@0 84
nuclear@0 85 if (base.length() == 0) {
nuclear@0 86 base = ".";
nuclear@0 87 base += getOsSeparator();
nuclear@0 88 }
nuclear@0 89 else if ((s = *(base.end()-1)) != '\\' && s != '/') {
nuclear@0 90 base += getOsSeparator();
nuclear@0 91 }
nuclear@0 92
nuclear@0 93 DefaultLogger::get()->info("Import root directory is \'" + base + "\'");
nuclear@0 94 }
nuclear@0 95
nuclear@0 96 /** Destructor. */
nuclear@0 97 ~FileSystemFilter()
nuclear@0 98 {
nuclear@0 99 // haha
nuclear@0 100 }
nuclear@0 101
nuclear@0 102 // -------------------------------------------------------------------
nuclear@0 103 /** Tests for the existence of a file at the given path. */
nuclear@0 104 bool Exists( const char* pFile) const
nuclear@0 105 {
nuclear@0 106 std::string tmp = pFile;
nuclear@0 107
nuclear@0 108 // Currently this IOSystem is also used to open THE ONE FILE.
nuclear@0 109 if (tmp != src_file) {
nuclear@0 110 BuildPath(tmp);
nuclear@0 111 Cleanup(tmp);
nuclear@0 112 }
nuclear@0 113
nuclear@0 114 return wrapped->Exists(tmp);
nuclear@0 115 }
nuclear@0 116
nuclear@0 117 // -------------------------------------------------------------------
nuclear@0 118 /** Returns the directory separator. */
nuclear@0 119 char getOsSeparator() const
nuclear@0 120 {
nuclear@0 121 return sep;
nuclear@0 122 }
nuclear@0 123
nuclear@0 124 // -------------------------------------------------------------------
nuclear@0 125 /** Open a new file with a given path. */
nuclear@0 126 IOStream* Open( const char* pFile, const char* pMode = "rb")
nuclear@0 127 {
nuclear@0 128 ai_assert(pFile);
nuclear@0 129 ai_assert(pMode);
nuclear@0 130
nuclear@0 131 // First try the unchanged path
nuclear@0 132 IOStream* s = wrapped->Open(pFile,pMode);
nuclear@0 133
nuclear@0 134 if (!s) {
nuclear@0 135 std::string tmp = pFile;
nuclear@0 136
nuclear@0 137 // Try to convert between absolute and relative paths
nuclear@0 138 BuildPath(tmp);
nuclear@0 139 s = wrapped->Open(tmp,pMode);
nuclear@0 140
nuclear@0 141 if (!s) {
nuclear@0 142 // Finally, look for typical issues with paths
nuclear@0 143 // and try to correct them. This is our last
nuclear@0 144 // resort.
nuclear@0 145 tmp = pFile;
nuclear@0 146 Cleanup(tmp);
nuclear@0 147 BuildPath(tmp);
nuclear@0 148 s = wrapped->Open(tmp,pMode);
nuclear@0 149 }
nuclear@0 150 }
nuclear@0 151
nuclear@0 152 return s;
nuclear@0 153 }
nuclear@0 154
nuclear@0 155 // -------------------------------------------------------------------
nuclear@0 156 /** Closes the given file and releases all resources associated with it. */
nuclear@0 157 void Close( IOStream* pFile)
nuclear@0 158 {
nuclear@0 159 return wrapped->Close(pFile);
nuclear@0 160 }
nuclear@0 161
nuclear@0 162 // -------------------------------------------------------------------
nuclear@0 163 /** Compare two paths */
nuclear@0 164 bool ComparePaths (const char* one, const char* second) const
nuclear@0 165 {
nuclear@0 166 return wrapped->ComparePaths (one,second);
nuclear@0 167 }
nuclear@0 168
nuclear@0 169 private:
nuclear@0 170
nuclear@0 171 // -------------------------------------------------------------------
nuclear@0 172 /** Build a valid path from a given relative or absolute path.
nuclear@0 173 */
nuclear@0 174 void BuildPath (std::string& in) const
nuclear@0 175 {
nuclear@0 176 // if we can already access the file, great.
nuclear@0 177 if (in.length() < 3 || wrapped->Exists(in)) {
nuclear@0 178 return;
nuclear@0 179 }
nuclear@0 180
nuclear@0 181 // Determine whether this is a relative path (Windows-specific - most assets are packaged on Windows).
nuclear@0 182 if (in[1] != ':') {
nuclear@0 183
nuclear@0 184 // append base path and try
nuclear@0 185 const std::string tmp = base + in;
nuclear@0 186 if (wrapped->Exists(tmp)) {
nuclear@0 187 in = tmp;
nuclear@0 188 return;
nuclear@0 189 }
nuclear@0 190 }
nuclear@0 191
nuclear@0 192 // Chop of the file name and look in the model directory, if
nuclear@0 193 // this fails try all sub paths of the given path, i.e.
nuclear@0 194 // if the given path is foo/bar/something.lwo, try
nuclear@0 195 // <base>/something.lwo
nuclear@0 196 // <base>/bar/something.lwo
nuclear@0 197 // <base>/foo/bar/something.lwo
nuclear@0 198 std::string::size_type pos = in.rfind('/');
nuclear@0 199 if (std::string::npos == pos) {
nuclear@0 200 pos = in.rfind('\\');
nuclear@0 201 }
nuclear@0 202
nuclear@0 203 if (std::string::npos != pos) {
nuclear@0 204 std::string tmp;
nuclear@0 205 std::string::size_type last_dirsep = std::string::npos;
nuclear@0 206
nuclear@0 207 while(true) {
nuclear@0 208 tmp = base;
nuclear@0 209 tmp += sep;
nuclear@0 210
nuclear@0 211 std::string::size_type dirsep = in.rfind('/', last_dirsep);
nuclear@0 212 if (std::string::npos == dirsep) {
nuclear@0 213 dirsep = in.rfind('\\', last_dirsep);
nuclear@0 214 }
nuclear@0 215
nuclear@0 216 if (std::string::npos == dirsep || dirsep == 0) {
nuclear@0 217 // we did try this already.
nuclear@0 218 break;
nuclear@0 219 }
nuclear@0 220
nuclear@0 221 last_dirsep = dirsep-1;
nuclear@0 222
nuclear@0 223 tmp += in.substr(dirsep+1, in.length()-pos);
nuclear@0 224 if (wrapped->Exists(tmp)) {
nuclear@0 225 in = tmp;
nuclear@0 226 return;
nuclear@0 227 }
nuclear@0 228 }
nuclear@0 229 }
nuclear@0 230
nuclear@0 231 // hopefully the underlying file system has another few tricks to access this file ...
nuclear@0 232 }
nuclear@0 233
nuclear@0 234 // -------------------------------------------------------------------
nuclear@0 235 /** Cleanup the given path
nuclear@0 236 */
nuclear@0 237 void Cleanup (std::string& in) const
nuclear@0 238 {
nuclear@0 239 char last = 0;
nuclear@0 240 if(in.empty()) {
nuclear@0 241 return;
nuclear@0 242 }
nuclear@0 243
nuclear@0 244 // Remove a very common issue when we're parsing file names: spaces at the
nuclear@0 245 // beginning of the path.
nuclear@0 246 std::string::iterator it = in.begin();
nuclear@0 247 while (IsSpaceOrNewLine( *it ))++it;
nuclear@0 248 if (it != in.begin()) {
nuclear@0 249 in.erase(in.begin(),it+1);
nuclear@0 250 }
nuclear@0 251
nuclear@0 252 const char sep = getOsSeparator();
nuclear@0 253 for (it = in.begin(); it != in.end(); ++it) {
nuclear@0 254 // Exclude :// and \\, which remain untouched.
nuclear@0 255 // https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
nuclear@0 256 if ( !strncmp(&*it, "://", 3 )) {
nuclear@0 257 it += 3;
nuclear@0 258 continue;
nuclear@0 259 }
nuclear@0 260 if (it == in.begin() && !strncmp(&*it, "\\\\", 2)) {
nuclear@0 261 it += 2;
nuclear@0 262 continue;
nuclear@0 263 }
nuclear@0 264
nuclear@0 265 // Cleanup path delimiters
nuclear@0 266 if (*it == '/' || (*it) == '\\') {
nuclear@0 267 *it = sep;
nuclear@0 268
nuclear@0 269 // And we're removing double delimiters, frequent issue with
nuclear@0 270 // incorrectly composited paths ...
nuclear@0 271 if (last == *it) {
nuclear@0 272 it = in.erase(it);
nuclear@0 273 --it;
nuclear@0 274 }
nuclear@0 275 }
nuclear@0 276 else if (*it == '%' && in.end() - it > 2) {
nuclear@0 277
nuclear@0 278 // Hex sequence in URIs
nuclear@0 279 if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) {
nuclear@0 280 *it = HexOctetToDecimal(&*it);
nuclear@0 281 it = in.erase(it+1,it+2);
nuclear@0 282 --it;
nuclear@0 283 }
nuclear@0 284 }
nuclear@0 285
nuclear@0 286 last = *it;
nuclear@0 287 }
nuclear@0 288 }
nuclear@0 289
nuclear@0 290 private:
nuclear@0 291 IOSystem* wrapped;
nuclear@0 292 std::string src_file, base;
nuclear@0 293 char sep;
nuclear@0 294 };
nuclear@0 295
nuclear@0 296 } //!ns Assimp
nuclear@0 297
nuclear@0 298 #endif //AI_DEFAULTIOSYSTEM_H_INC