/src/assimp/code/Common/DefaultIOStream.cpp
Line | Count | Source |
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 DefaultIOStream.cpp |
42 | | * @brief Default File I/O implementation for #Importer |
43 | | */ |
44 | | |
45 | | #include <assimp/DefaultIOStream.h> |
46 | | #include <assimp/ai_assert.h> |
47 | | #include <sys/stat.h> |
48 | | #include <sys/types.h> |
49 | | |
50 | | using namespace Assimp; |
51 | | |
52 | | namespace { |
53 | | |
54 | | template <size_t sizeOfPointer> |
55 | 0 | inline size_t select_ftell(FILE *file) { |
56 | 0 | return ::ftell(file); |
57 | 0 | } |
58 | | |
59 | | template <size_t sizeOfPointer> |
60 | 0 | inline int select_fseek(FILE *file, int64_t offset, int origin) { |
61 | 0 | return ::fseek(file, static_cast<long>(offset), origin); |
62 | 0 | } |
63 | | |
64 | | |
65 | | |
66 | | #if defined _WIN32 && (!defined __GNUC__ || !defined __CLANG__ && __MSVCRT_VERSION__ >= 0x0601) |
67 | | template <> |
68 | | inline size_t select_ftell<8>(FILE *file) { |
69 | | return (size_t)::_ftelli64(file); |
70 | | } |
71 | | |
72 | | template <> |
73 | | inline int select_fseek<8>(FILE *file, int64_t offset, int origin) { |
74 | | return ::_fseeki64(file, offset, origin); |
75 | | } |
76 | | |
77 | | #endif |
78 | | |
79 | | } // namespace |
80 | | |
81 | | // ---------------------------------------------------------------------------------- |
82 | 0 | DefaultIOStream::~DefaultIOStream() { |
83 | 0 | if (mFile) { |
84 | 0 | ::fclose(mFile); |
85 | 0 | } |
86 | 0 | } |
87 | | |
88 | | // ---------------------------------------------------------------------------------- |
89 | | size_t DefaultIOStream::Read(void *pvBuffer, |
90 | | size_t pSize, |
91 | 0 | size_t pCount) { |
92 | 0 | if (0 == pCount) { |
93 | 0 | return 0; |
94 | 0 | } |
95 | 0 | ai_assert(nullptr != pvBuffer); |
96 | 0 | ai_assert(0 != pSize); |
97 | |
|
98 | 0 | return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0); |
99 | 0 | } |
100 | | |
101 | | // ---------------------------------------------------------------------------------- |
102 | | size_t DefaultIOStream::Write(const void *pvBuffer, |
103 | | size_t pSize, |
104 | 0 | size_t pCount) { |
105 | 0 | ai_assert(nullptr != pvBuffer); |
106 | 0 | ai_assert(0 != pSize); |
107 | |
|
108 | 0 | return (mFile ? ::fwrite(pvBuffer, pSize, pCount, mFile) : 0); |
109 | 0 | } |
110 | | |
111 | | // ---------------------------------------------------------------------------------- |
112 | | aiReturn DefaultIOStream::Seek(size_t pOffset, |
113 | 0 | aiOrigin pOrigin) { |
114 | 0 | if (!mFile) { |
115 | 0 | return AI_FAILURE; |
116 | 0 | } |
117 | | |
118 | | // Just to check whether our enum maps one to one with the CRT constants |
119 | 0 | static_assert(aiOrigin_CUR == SEEK_CUR && |
120 | 0 | aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET, |
121 | 0 | "aiOrigin_CUR == SEEK_CUR && \ |
122 | 0 | aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET"); |
123 | | |
124 | | // do the seek |
125 | 0 | return (0 == select_fseek<sizeof(void *)>(mFile, (int64_t)pOffset, (int)pOrigin) ? AI_SUCCESS : AI_FAILURE); |
126 | 0 | } |
127 | | |
128 | | // ---------------------------------------------------------------------------------- |
129 | 0 | size_t DefaultIOStream::Tell() const { |
130 | 0 | if (!mFile) { |
131 | 0 | return 0; |
132 | 0 | } |
133 | 0 | return select_ftell<sizeof(void *)>(mFile); |
134 | 0 | } |
135 | | |
136 | | // ---------------------------------------------------------------------------------- |
137 | 0 | size_t DefaultIOStream::FileSize() const { |
138 | 0 | if (!mFile || mFilename.empty()) { |
139 | 0 | return 0; |
140 | 0 | } |
141 | | |
142 | 0 | if (SIZE_MAX == mCachedSize) { |
143 | | |
144 | | // Although fseek/ftell would allow us to reuse the existing file handle here, |
145 | | // it is generally unsafe because: |
146 | | // - For binary streams, it is not technically well-defined |
147 | | // - For text files the results are meaningless |
148 | | // That's why we use the safer variant fstat here. |
149 | | // |
150 | | // See here for details: |
151 | | // https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file |
152 | | #if defined _WIN32 && (!defined __GNUC__ || !defined __CLANG__ && __MSVCRT_VERSION__ >= 0x0601) |
153 | | struct __stat64 fileStat; |
154 | | //using fileno + fstat avoids having to handle the filename |
155 | | int err = _fstat64(_fileno(mFile), &fileStat); |
156 | | if (0 != err) |
157 | | return 0; |
158 | | mCachedSize = (size_t)(fileStat.st_size); |
159 | | #elif defined _WIN32 |
160 | | struct _stat fileStat; |
161 | | //using fileno + fstat avoids having to handle the filename |
162 | | int err = _fstat(_fileno(mFile), &fileStat); |
163 | | if (0 != err) |
164 | | return 0; |
165 | | mCachedSize = (size_t)(fileStat.st_size); |
166 | | #elif defined __GNUC__ || defined __APPLE__ || defined __MACH__ || defined __FreeBSD__ |
167 | | struct stat fileStat; |
168 | 0 | int err = stat(mFilename.c_str(), &fileStat); |
169 | 0 | if (0 != err) |
170 | 0 | return 0; |
171 | 0 | const unsigned long long cachedSize = fileStat.st_size; |
172 | 0 | mCachedSize = static_cast<size_t>(cachedSize); |
173 | | #else |
174 | | #error "Unknown platform" |
175 | | #endif |
176 | 0 | } |
177 | 0 | return mCachedSize; |
178 | 0 | } |
179 | | |
180 | | // ---------------------------------------------------------------------------------- |
181 | 0 | void DefaultIOStream::Flush() { |
182 | 0 | if (mFile) { |
183 | 0 | ::fflush(mFile); |
184 | 0 | } |
185 | 0 | } |
186 | | |
187 | | // ---------------------------------------------------------------------------------- |