/src/assimp/code/Common/DefaultIOSystem.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | --------------------------------------------------------------------------- |
3 | | Open Asset Import Library (assimp) |
4 | | --------------------------------------------------------------------------- |
5 | | |
6 | | Copyright (c) 2006-2025, 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 | 96.1k | bool DefaultIOSystem::Exists(const char *pFile) const { |
96 | 96.1k | if (pFile == nullptr) { |
97 | 0 | return false; |
98 | 0 | } |
99 | | |
100 | | #ifdef _WIN32 |
101 | | struct __stat64 filestat; |
102 | | if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) { |
103 | | return false; |
104 | | } |
105 | | #else |
106 | 96.1k | struct stat statbuf; |
107 | 96.1k | if (stat(pFile, &statbuf) != 0) { |
108 | 93.8k | return false; |
109 | 93.8k | } |
110 | | // test for a regular file |
111 | 2.35k | if (!S_ISREG(statbuf.st_mode)) { |
112 | 2.35k | return false; |
113 | 2.35k | } |
114 | 0 | #endif |
115 | | |
116 | 0 | return true; |
117 | 2.35k | } |
118 | | |
119 | | // ------------------------------------------------------------------------------------------------ |
120 | | // Open a new file with a given path. |
121 | 3.31k | IOStream *DefaultIOSystem::Open(const char *strFile, const char *strMode) { |
122 | 3.31k | ai_assert(strFile != nullptr); |
123 | 3.31k | ai_assert(strMode != nullptr); |
124 | 3.31k | FILE *file; |
125 | | |
126 | | #ifdef _WIN32 |
127 | | std::wstring name = Utf8ToWide(strFile); |
128 | | if (name.empty()) { |
129 | | return nullptr; |
130 | | } |
131 | | |
132 | | file = ::_wfopen(name.c_str(), Utf8ToWide(strMode).c_str()); |
133 | | #else |
134 | 3.31k | file = ::fopen(strFile, strMode); |
135 | 3.31k | #endif |
136 | | |
137 | 3.31k | if (!file) { |
138 | 3.31k | return nullptr; |
139 | 3.31k | } |
140 | | |
141 | 0 | return new DefaultIOStream(file, strFile); |
142 | 3.31k | } |
143 | | |
144 | | // ------------------------------------------------------------------------------------------------ |
145 | | // Closes the given file and releases all resources associated with it. |
146 | 0 | void DefaultIOSystem::Close(IOStream *pFile) { |
147 | 0 | delete pFile; |
148 | 0 | } |
149 | | |
150 | | // ------------------------------------------------------------------------------------------------ |
151 | | // Returns the operation specific directory separator |
152 | 1.05k | char DefaultIOSystem::getOsSeparator() const { |
153 | 1.05k | #ifndef _WIN32 |
154 | 1.05k | return '/'; |
155 | | #else |
156 | | return '\\'; |
157 | | #endif |
158 | 1.05k | } |
159 | | |
160 | | // ------------------------------------------------------------------------------------------------ |
161 | | // IOSystem default implementation (ComparePaths isn't a pure virtual function) |
162 | 0 | bool IOSystem::ComparePaths(const char *one, const char *second) const { |
163 | 0 | return !ASSIMP_stricmp(one, second); |
164 | 0 | } |
165 | | |
166 | | // ------------------------------------------------------------------------------------------------ |
167 | | // Convert a relative path into an absolute path |
168 | 36.1k | inline static std::string MakeAbsolutePath(const char *in) { |
169 | 36.1k | ai_assert(in); |
170 | 36.1k | std::string out; |
171 | | #ifdef _WIN32 |
172 | | wchar_t *ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0); |
173 | | if (ret) { |
174 | | out = WideToUtf8(ret); |
175 | | free(ret); |
176 | | } |
177 | | #else |
178 | 36.1k | char *ret = realpath(in, nullptr); |
179 | 36.1k | if (ret) { |
180 | 0 | out = ret; |
181 | 0 | free(ret); |
182 | 0 | } |
183 | 36.1k | #endif |
184 | 36.1k | else { |
185 | | // preserve the input path, maybe someone else is able to fix |
186 | | // the path before it is accessed (e.g. our file system filter) |
187 | 36.1k | ASSIMP_LOG_WARN("Invalid path: ", std::string(in)); |
188 | 36.1k | out = in; |
189 | 36.1k | } |
190 | 36.1k | return out; |
191 | 36.1k | } |
192 | | |
193 | | // ------------------------------------------------------------------------------------------------ |
194 | | // DefaultIOSystem's more specialized implementation |
195 | 24.8k | bool DefaultIOSystem::ComparePaths(const char *one, const char *second) const { |
196 | | // chances are quite good both paths are formatted identically, |
197 | | // so we can hopefully return here already |
198 | 24.8k | if (!ASSIMP_stricmp(one, second)) |
199 | 6.79k | return true; |
200 | | |
201 | 18.0k | std::string temp1 = MakeAbsolutePath(one); |
202 | 18.0k | std::string temp2 = MakeAbsolutePath(second); |
203 | | |
204 | 18.0k | return !ASSIMP_stricmp(temp1, temp2); |
205 | 24.8k | } |
206 | | |
207 | | // ------------------------------------------------------------------------------------------------ |
208 | 1.63k | std::string DefaultIOSystem::fileName(const std::string &path) { |
209 | 1.63k | std::string ret = path; |
210 | 1.63k | std::size_t last = ret.find_last_of("\\/"); |
211 | 1.63k | if (last != std::string::npos) ret = ret.substr(last + 1); |
212 | 1.63k | return ret; |
213 | 1.63k | } |
214 | | |
215 | | // ------------------------------------------------------------------------------------------------ |
216 | 1.63k | std::string DefaultIOSystem::completeBaseName(const std::string &path) { |
217 | 1.63k | std::string ret = fileName(path); |
218 | 1.63k | std::size_t pos = ret.find_last_of('.'); |
219 | 1.63k | if (pos != std::string::npos) ret = ret.substr(0, pos); |
220 | 1.63k | return ret; |
221 | 1.63k | } |
222 | | |
223 | | // ------------------------------------------------------------------------------------------------ |
224 | 4 | std::string DefaultIOSystem::absolutePath(const std::string &path) { |
225 | 4 | std::string ret = path; |
226 | 4 | std::size_t last = ret.find_last_of("\\/"); |
227 | 4 | if (last != std::string::npos) ret = ret.substr(0, last); |
228 | 4 | return ret; |
229 | 4 | } |
230 | | |
231 | | // ------------------------------------------------------------------------------------------------ |