1 | /* |
2 | --------------------------------------------------------------------------- |
3 | Open Asset Import Library (assimp) |
4 | --------------------------------------------------------------------------- |
5 | |
6 | Copyright (c) 2006-2022, assimp team |
7 | |
8 | All rights reserved. |
9 | |
10 | Redistribution and use of this software in source and binary forms, |
11 | with or without modification, are permitted provided that the following |
12 | conditions are met: |
13 | |
14 | * Redistributions of source code must retain the above |
15 | copyright notice, this list of conditions and the |
16 | following disclaimer. |
17 | |
18 | * Redistributions in binary form must reproduce the above |
19 | copyright notice, this list of conditions and the |
20 | following disclaimer in the documentation and/or other |
21 | materials provided with the distribution. |
22 | |
23 | * Neither the name of the assimp team, nor the names of its |
24 | contributors may be used to endorse or promote products |
25 | derived from this software without specific prior |
26 | written permission of the assimp team. |
27 | |
28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
29 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
31 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
32 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
33 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
34 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
35 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
36 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
37 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
38 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
39 | --------------------------------------------------------------------------- |
40 | */ |
41 | /** @file Default implementation of IOSystem using the standard C file functions */ |
42 | |
43 | #include <assimp/StringComparison.h> |
44 | |
45 | #include <assimp/DefaultIOStream.h> |
46 | #include <assimp/DefaultIOSystem.h> |
47 | #include <assimp/ai_assert.h> |
48 | #include <stdlib.h> |
49 | #include <assimp/DefaultLogger.hpp> |
50 | |
51 | #ifdef __unix__ |
52 | # include <stdlib.h> |
53 | # include <sys/param.h> |
54 | #endif |
55 | |
56 | #ifdef _WIN32 |
57 | # include <windows.h> |
58 | #endif |
59 | |
60 | using namespace Assimp; |
61 | |
62 | #ifdef _WIN32 |
63 | |
64 | const std::wstring wdummy; |
65 | |
66 | static std::wstring Utf8ToWide(const char *in) { |
67 | if (nullptr == in) { |
68 | return wdummy; |
69 | } |
70 | int size = MultiByteToWideChar(CP_UTF8, 0, in, -1, nullptr, 0); |
71 | // size includes terminating null; std::wstring adds null automatically |
72 | std::wstring out(static_cast<size_t>(size) - 1, L'\0'); |
73 | MultiByteToWideChar(CP_UTF8, 0, in, -1, &out[0], size); |
74 | |
75 | return out; |
76 | } |
77 | |
78 | const std::string dummy; |
79 | |
80 | static std::string WideToUtf8(const wchar_t *in) { |
81 | if (nullptr == in) { |
82 | return dummy; |
83 | } |
84 | int size = WideCharToMultiByte(CP_UTF8, 0, in, -1, nullptr, 0, nullptr, nullptr); |
85 | // size includes terminating null; std::string adds null automatically |
86 | std::string out(static_cast<size_t>(size) - 1, '\0'); |
87 | WideCharToMultiByte(CP_UTF8, 0, in, -1, &out[0], size, nullptr, nullptr); |
88 | |
89 | return out; |
90 | } |
91 | #endif |
92 | |
93 | // ------------------------------------------------------------------------------------------------ |
94 | // Tests for the existence of a file at the given path. |
95 | bool DefaultIOSystem::Exists(const char *pFile) const { |
96 | #ifdef _WIN32 |
97 | struct __stat64 filestat; |
98 | if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) { |
99 | return false; |
100 | } |
101 | #else |
102 | FILE *file = ::fopen(filename: pFile, modes: "rb" ); |
103 | if (!file) { |
104 | return false; |
105 | } |
106 | |
107 | ::fclose(stream: file); |
108 | #endif |
109 | |
110 | return true; |
111 | } |
112 | |
113 | // ------------------------------------------------------------------------------------------------ |
114 | // Open a new file with a given path. |
115 | IOStream *DefaultIOSystem::Open(const char *strFile, const char *strMode) { |
116 | ai_assert(strFile != nullptr); |
117 | ai_assert(strMode != nullptr); |
118 | FILE *file; |
119 | #ifdef _WIN32 |
120 | std::wstring name = Utf8ToWide(strFile); |
121 | if (name.empty()) { |
122 | return nullptr; |
123 | } |
124 | |
125 | file = ::_wfopen(name.c_str(), Utf8ToWide(strMode).c_str()); |
126 | #else |
127 | file = ::fopen(filename: strFile, modes: strMode); |
128 | #endif |
129 | if (!file) { |
130 | return nullptr; |
131 | } |
132 | |
133 | return new DefaultIOStream(file, strFile); |
134 | } |
135 | |
136 | // ------------------------------------------------------------------------------------------------ |
137 | // Closes the given file and releases all resources associated with it. |
138 | void DefaultIOSystem::Close(IOStream *pFile) { |
139 | delete pFile; |
140 | } |
141 | |
142 | // ------------------------------------------------------------------------------------------------ |
143 | // Returns the operation specific directory separator |
144 | char DefaultIOSystem::getOsSeparator() const { |
145 | #ifndef _WIN32 |
146 | return '/'; |
147 | #else |
148 | return '\\'; |
149 | #endif |
150 | } |
151 | |
152 | // ------------------------------------------------------------------------------------------------ |
153 | // IOSystem default implementation (ComparePaths isn't a pure virtual function) |
154 | bool IOSystem::ComparePaths(const char *one, const char *second) const { |
155 | return !ASSIMP_stricmp(s1: one, s2: second); |
156 | } |
157 | |
158 | // ------------------------------------------------------------------------------------------------ |
159 | // Convert a relative path into an absolute path |
160 | inline static std::string MakeAbsolutePath(const char *in) { |
161 | ai_assert(in); |
162 | std::string out; |
163 | #ifdef _WIN32 |
164 | wchar_t *ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0); |
165 | if (ret) { |
166 | out = WideToUtf8(ret); |
167 | free(ret); |
168 | } |
169 | #else |
170 | char *ret = realpath(name: in, resolved: nullptr); |
171 | if (ret) { |
172 | out = ret; |
173 | free(ptr: ret); |
174 | } |
175 | #endif |
176 | else { |
177 | // preserve the input path, maybe someone else is able to fix |
178 | // the path before it is accessed (e.g. our file system filter) |
179 | ASSIMP_LOG_WARN("Invalid path: " , std::string(in)); |
180 | out = in; |
181 | } |
182 | return out; |
183 | } |
184 | |
185 | // ------------------------------------------------------------------------------------------------ |
186 | // DefaultIOSystem's more specialized implementation |
187 | bool DefaultIOSystem::ComparePaths(const char *one, const char *second) const { |
188 | // chances are quite good both paths are formatted identically, |
189 | // so we can hopefully return here already |
190 | if (!ASSIMP_stricmp(s1: one, s2: second)) |
191 | return true; |
192 | |
193 | std::string temp1 = MakeAbsolutePath(in: one); |
194 | std::string temp2 = MakeAbsolutePath(in: second); |
195 | |
196 | return !ASSIMP_stricmp(a: temp1, b: temp2); |
197 | } |
198 | |
199 | // ------------------------------------------------------------------------------------------------ |
200 | std::string DefaultIOSystem::fileName(const std::string &path) { |
201 | std::string ret = path; |
202 | std::size_t last = ret.find_last_of(s: "\\/" ); |
203 | if (last != std::string::npos) ret = ret.substr(pos: last + 1); |
204 | return ret; |
205 | } |
206 | |
207 | // ------------------------------------------------------------------------------------------------ |
208 | std::string DefaultIOSystem::completeBaseName(const std::string &path) { |
209 | std::string ret = fileName(path); |
210 | std::size_t pos = ret.find_last_of(c: '.'); |
211 | if (pos != std::string::npos) ret = ret.substr(pos: 0, n: pos); |
212 | return ret; |
213 | } |
214 | |
215 | // ------------------------------------------------------------------------------------------------ |
216 | std::string DefaultIOSystem::absolutePath(const std::string &path) { |
217 | std::string ret = path; |
218 | std::size_t last = ret.find_last_of(s: "\\/" ); |
219 | if (last != std::string::npos) ret = ret.substr(pos: 0, n: last); |
220 | return ret; |
221 | } |
222 | |
223 | // ------------------------------------------------------------------------------------------------ |
224 | |