vrshoot

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