/src/assimp/code/AssetLib/Obj/ObjTools.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Open Asset Import Library (assimp) |
3 | | ---------------------------------------------------------------------- |
4 | | |
5 | | Copyright (c) 2006-2025, assimp team |
6 | | |
7 | | All rights reserved. |
8 | | |
9 | | Redistribution and use of this software in source and binary forms, |
10 | | with or without modification, are permitted provided that the |
11 | | following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above |
14 | | copyright notice, this list of conditions and the |
15 | | following disclaimer. |
16 | | |
17 | | * Redistributions in binary form must reproduce the above |
18 | | copyright notice, this list of conditions and the |
19 | | following disclaimer in the documentation and/or other |
20 | | materials provided with the distribution. |
21 | | |
22 | | * Neither the name of the assimp team, nor the names of its |
23 | | contributors may be used to endorse or promote products |
24 | | derived from this software without specific prior |
25 | | written permission of the assimp team. |
26 | | |
27 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | | |
39 | | ---------------------------------------------------------------------- |
40 | | */ |
41 | | |
42 | | /** @file ObjTools.h |
43 | | * @brief Some helpful templates for text parsing |
44 | | */ |
45 | | #ifndef OBJ_TOOLS_H_INC |
46 | | #define OBJ_TOOLS_H_INC |
47 | | |
48 | | #include <assimp/ParsingUtils.h> |
49 | | #include <assimp/fast_atof.h> |
50 | | #include <vector> |
51 | | |
52 | | namespace Assimp { |
53 | | |
54 | | /** |
55 | | * @brief Returns true, if the last entry of the buffer is reached. |
56 | | * @param[in] it Iterator of current position. |
57 | | * @param[in] end Iterator with end of buffer. |
58 | | * @return true, if the end of the buffer is reached. |
59 | | */ |
60 | | template <class char_t> |
61 | 28.5M | inline bool isEndOfBuffer(char_t it, char_t end) { |
62 | 28.5M | if (it == end) { |
63 | 0 | return true; |
64 | 0 | } |
65 | 28.5M | --end; |
66 | | |
67 | 28.5M | return (it == end); |
68 | 28.5M | } |
69 | | |
70 | | /** |
71 | | * @brief Returns next word separated by a space |
72 | | * @param[in] pBuffer Pointer to data buffer |
73 | | * @param[in] pEnd Pointer to end of buffer |
74 | | * @return Pointer to next space |
75 | | */ |
76 | | template <class Char_T> |
77 | 205k | inline Char_T getNextWord(Char_T pBuffer, Char_T pEnd) { |
78 | 518k | while (!isEndOfBuffer(pBuffer, pEnd)) { |
79 | 518k | if (!IsSpaceOrNewLine(*pBuffer) || IsLineEnd(*pBuffer)) { |
80 | 205k | break; |
81 | 205k | } |
82 | 312k | ++pBuffer; |
83 | 312k | } |
84 | | |
85 | 205k | return pBuffer; |
86 | 205k | } |
87 | | |
88 | | /** |
89 | | * @brief Returns pointer a next token |
90 | | * @param[in] pBuffer Pointer to data buffer |
91 | | * @param[in] pEnd Pointer to end of buffer |
92 | | * @return Pointer to next token |
93 | | */ |
94 | | template <class Char_T> |
95 | 160k | inline Char_T getNextToken(Char_T pBuffer, Char_T pEnd) { |
96 | 2.06M | while (!isEndOfBuffer(pBuffer, pEnd)) { |
97 | 2.06M | if (IsSpaceOrNewLine(*pBuffer)) { |
98 | 160k | break; |
99 | 160k | } |
100 | 1.90M | ++pBuffer; |
101 | 1.90M | } |
102 | 160k | return getNextWord(pBuffer, pEnd); |
103 | 160k | } |
104 | | |
105 | | /** |
106 | | * @brief Skips a line |
107 | | * @param[in] it Iterator set to current position |
108 | | * @param[in] end Iterator set to end of scratch buffer for readout |
109 | | * @param[out] uiLine Current line number in format |
110 | | * @return Current-iterator with new position |
111 | | */ |
112 | | template <class char_t> |
113 | 4.59M | inline char_t skipLine(char_t it, char_t end, unsigned int &uiLine) { |
114 | 4.59M | if (it >= end) { |
115 | 179 | return it; |
116 | 179 | } |
117 | | |
118 | 24.9M | while (!isEndOfBuffer(it, end) && !IsLineEnd(*it)) { |
119 | 20.3M | ++it; |
120 | 20.3M | } |
121 | | |
122 | 4.59M | if (it != end) { |
123 | 4.59M | ++it; |
124 | 4.59M | ++uiLine; |
125 | 4.59M | } |
126 | | // fix .. from time to time there are spaces at the beginning of a material line |
127 | 5.08M | while (it != end && (*it == '\t' || *it == ' ')) { |
128 | 491k | ++it; |
129 | 491k | } |
130 | | |
131 | 4.59M | return it; |
132 | 4.59M | } |
133 | | |
134 | | /** |
135 | | * @brief Get a name from the current line. Preserve space in the middle, |
136 | | * but trim it at the end. |
137 | | * @param[in] it set to current position |
138 | | * @param[in] end set to end of scratch buffer for readout |
139 | | * @param[out] name Separated name |
140 | | * @return Current-iterator with new position |
141 | | */ |
142 | | template <class char_t> |
143 | 84.3k | inline char_t getName(char_t it, char_t end, std::string &name) { |
144 | 84.3k | name = ""; |
145 | 84.3k | if (isEndOfBuffer(it, end)) { |
146 | 179 | return end; |
147 | 179 | } |
148 | | |
149 | 84.1k | char *pStart = &(*it); |
150 | 506k | while (!isEndOfBuffer(it, end) && !IsLineEnd(*it)) { |
151 | 422k | ++it; |
152 | 422k | } |
153 | | |
154 | 84.1k | while (IsSpace(*it)) { |
155 | 0 | --it; |
156 | 0 | } |
157 | | // Get name |
158 | | // if there is no name, and the previous char is a separator, come back to start |
159 | 84.1k | while (&(*it) < pStart) { |
160 | 0 | ++it; |
161 | 0 | } |
162 | 84.1k | std::string strName(pStart, &(*it)); |
163 | 84.1k | if (!strName.empty()) { |
164 | 30.1k | name = strName; |
165 | 30.1k | } |
166 | | |
167 | | |
168 | 84.1k | return it; |
169 | 84.3k | } |
170 | | |
171 | | /** |
172 | | * @brief Get a name from the current line. Do not preserve space |
173 | | * in the middle, but trim it at the end. |
174 | | * @param it set to current position |
175 | | * @param end set to end of scratch buffer for readout |
176 | | * @param name Separated name |
177 | | * @return Current-iterator with new position |
178 | | */ |
179 | | template <class char_t> |
180 | 11.6k | inline char_t getNameNoSpace(char_t it, char_t end, std::string &name) { |
181 | 11.6k | name = ""; |
182 | 11.6k | if (isEndOfBuffer(it, end)) { |
183 | 0 | return end; |
184 | 0 | } |
185 | | |
186 | 11.6k | char *pStart = &(*it); |
187 | 122k | while (!isEndOfBuffer(it, end) && !IsLineEnd(*it) && !IsSpaceOrNewLine(*it)) { |
188 | 111k | ++it; |
189 | 111k | } |
190 | | |
191 | 23.3k | while (isEndOfBuffer(it, end) || IsLineEnd(*it) || IsSpaceOrNewLine(*it)) { |
192 | 11.6k | --it; |
193 | 11.6k | } |
194 | 11.6k | ++it; |
195 | | |
196 | | // Get name |
197 | | // if there is no name, and the previous char is a separator, come back to start |
198 | 11.6k | while (&(*it) < pStart) { |
199 | 0 | ++it; |
200 | 0 | } |
201 | 11.6k | std::string strName(pStart, &(*it)); |
202 | 11.6k | if (!strName.empty()) { |
203 | 11.6k | name = strName; |
204 | 11.6k | } |
205 | | |
206 | 11.6k | return it; |
207 | 11.6k | } |
208 | | |
209 | | /** |
210 | | * @brief Get next word from given line |
211 | | * @param[in] it set to current position |
212 | | * @param[in] end set to end of scratch buffer for readout |
213 | | * @param[in] pBuffer Buffer for next word |
214 | | * @param[in] length Buffer length |
215 | | * @return Current-iterator with new position |
216 | | */ |
217 | | template <class char_t> |
218 | 27.6k | inline char_t CopyNextWord(char_t it, char_t end, char *pBuffer, size_t length) { |
219 | 27.6k | size_t index = 0; |
220 | 27.6k | it = getNextWord<char_t>(it, end); |
221 | 221k | while (!IsSpaceOrNewLine(*it) && !isEndOfBuffer(it, end)) { |
222 | 196k | pBuffer[index] = *it; |
223 | 196k | ++index; |
224 | 196k | if (index == length - 1) { |
225 | 2.41k | break; |
226 | 2.41k | } |
227 | 193k | ++it; |
228 | 193k | } |
229 | 27.6k | pBuffer[index] = '\0'; |
230 | 27.6k | return it; |
231 | 27.6k | } |
232 | | |
233 | | /** |
234 | | * @brief Get next float from given line |
235 | | * @param[in] it set to current position |
236 | | * @param[in] end set to end of scratch buffer for readout |
237 | | * @param[out] value Separated float value. |
238 | | * @return Current-iterator with new position |
239 | | */ |
240 | | template <class char_t> |
241 | 1.10k | inline char_t getFloat(char_t it, char_t end, ai_real &value) { |
242 | 1.10k | static const size_t BUFFERSIZE = 1024; |
243 | 1.10k | char buffer[BUFFERSIZE] = {}; |
244 | 1.10k | it = CopyNextWord<char_t>(it, end, buffer, BUFFERSIZE); |
245 | 1.10k | value = (ai_real)fast_atof(buffer); |
246 | | |
247 | 1.10k | return it; |
248 | 1.10k | } |
249 | | |
250 | | /** |
251 | | * @brief Checks for a line-end. |
252 | | * @param[in] it Current iterator in string. |
253 | | * @param[in] end End of the string. |
254 | | * @return The trimmed string. |
255 | | */ |
256 | | template <class T> |
257 | | bool hasLineEnd(T it, T end) { |
258 | | bool hasLineEnd = false; |
259 | | while (!isEndOfBuffer(it, end)) { |
260 | | ++it; |
261 | | if (IsLineEnd(it)) { |
262 | | hasLineEnd = true; |
263 | | break; |
264 | | } |
265 | | } |
266 | | |
267 | | return hasLineEnd; |
268 | | } |
269 | | |
270 | | } // Namespace Assimp |
271 | | |
272 | | #endif // OBJ_TOOLS_H_INC |