1 | /* |
2 | Open Asset Import Library (assimp) |
3 | ---------------------------------------------------------------------- |
4 | |
5 | Copyright (c) 2006-2017, 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 "fast_atof.h" |
49 | #include "ParsingUtils.h" |
50 | #include <vector> |
51 | |
52 | namespace Assimp { |
53 | |
54 | /** @brief Returns true, if the last entry of the buffer is reached. |
55 | * @param it Iterator of current position. |
56 | * @param end Iterator with end of buffer. |
57 | * @return true, if the end of the buffer is reached. |
58 | */ |
59 | template<class char_t> |
60 | inline bool isEndOfBuffer( char_t it, char_t end ) { |
61 | if ( it == end ) |
62 | { |
63 | return true; |
64 | } |
65 | else |
66 | { |
67 | --end; |
68 | } |
69 | return ( it == end ); |
70 | } |
71 | |
72 | /** @brief Returns next word separated by a space |
73 | * @param pBuffer Pointer to data buffer |
74 | * @param pEnd Pointer to end of buffer |
75 | * @return Pointer to next space |
76 | */ |
77 | template<class Char_T> |
78 | inline Char_T getNextWord( Char_T pBuffer, Char_T pEnd ) |
79 | { |
80 | while ( !isEndOfBuffer( pBuffer, pEnd ) ) |
81 | { |
82 | if ( !IsSpaceOrNewLine( *pBuffer ) || IsLineEnd( *pBuffer ) ) { |
83 | //if ( *pBuffer != '\\' ) |
84 | break; |
85 | } |
86 | pBuffer++; |
87 | } |
88 | return pBuffer; |
89 | } |
90 | |
91 | /** @brief Returns pointer a next token |
92 | * @param pBuffer Pointer to data buffer |
93 | * @param pEnd Pointer to end of buffer |
94 | * @return Pointer to next token |
95 | */ |
96 | template<class Char_T> |
97 | inline Char_T getNextToken( Char_T pBuffer, Char_T pEnd ) |
98 | { |
99 | while ( !isEndOfBuffer( pBuffer, pEnd ) ) |
100 | { |
101 | if( IsSpaceOrNewLine( *pBuffer ) ) |
102 | break; |
103 | pBuffer++; |
104 | } |
105 | return getNextWord( pBuffer, pEnd ); |
106 | } |
107 | |
108 | /** @brief Skips a line |
109 | * @param it Iterator set to current position |
110 | * @param end Iterator set to end of scratch buffer for readout |
111 | * @param uiLine Current line number in format |
112 | * @return Current-iterator with new position |
113 | */ |
114 | template<class char_t> |
115 | inline char_t skipLine( char_t it, char_t end, unsigned int &uiLine ) { |
116 | while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) ) { |
117 | ++it; |
118 | } |
119 | |
120 | if ( it != end ) { |
121 | ++it; |
122 | ++uiLine; |
123 | } |
124 | // fix .. from time to time there are spaces at the beginning of a material line |
125 | while ( it != end && ( *it == '\t' || *it == ' ' ) ) { |
126 | ++it; |
127 | } |
128 | |
129 | return it; |
130 | } |
131 | |
132 | /** @brief Get a name from the current line. Preserve space in the middle, |
133 | * but trim it at the end. |
134 | * @param it set to current position |
135 | * @param end set to end of scratch buffer for readout |
136 | * @param name Separated name |
137 | * @return Current-iterator with new position |
138 | */ |
139 | template<class char_t> |
140 | inline char_t getName( char_t it, char_t end, std::string &name ) |
141 | { |
142 | name = "" ; |
143 | if( isEndOfBuffer( it, end ) ) { |
144 | return end; |
145 | } |
146 | |
147 | char *pStart = &( *it ); |
148 | while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it )) { |
149 | ++it; |
150 | } |
151 | |
152 | while(IsSpace( *it ) ) { |
153 | --it; |
154 | } |
155 | // Get name |
156 | // if there is no name, and the previous char is a separator, come back to start |
157 | while (&(*it) < pStart) { |
158 | ++it; |
159 | } |
160 | std::string strName( pStart, &(*it) ); |
161 | if ( strName.empty() ) |
162 | return it; |
163 | else |
164 | name = strName; |
165 | |
166 | return it; |
167 | } |
168 | |
169 | /** @brief Get a name from the current line. Do not preserve space |
170 | * in the middle, but trim it at the end. |
171 | * @param it set to current position |
172 | * @param end set to end of scratch buffer for readout |
173 | * @param name Separated name |
174 | * @return Current-iterator with new position |
175 | */ |
176 | template<class char_t> |
177 | inline char_t getNameNoSpace( char_t it, char_t end, std::string &name ) |
178 | { |
179 | name = "" ; |
180 | if( isEndOfBuffer( it, end ) ) { |
181 | return end; |
182 | } |
183 | |
184 | char *pStart = &( *it ); |
185 | while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) |
186 | && !IsSpaceOrNewLine( *it ) ) { |
187 | ++it; |
188 | } |
189 | |
190 | while( isEndOfBuffer( it, end ) || IsLineEnd( *it ) |
191 | || IsSpaceOrNewLine( *it ) ) { |
192 | --it; |
193 | } |
194 | ++it; |
195 | |
196 | // Get name |
197 | // if there is no name, and the previous char is a separator, come back to start |
198 | while (&(*it) < pStart) { |
199 | ++it; |
200 | } |
201 | std::string strName( pStart, &(*it) ); |
202 | if ( strName.empty() ) |
203 | return it; |
204 | else |
205 | name = strName; |
206 | |
207 | return it; |
208 | } |
209 | |
210 | /** @brief Get next word from given line |
211 | * @param it set to current position |
212 | * @param end set to end of scratch buffer for readout |
213 | * @param pBuffer Buffer for next word |
214 | * @param length Buffer length |
215 | * @return Current-iterator with new position |
216 | */ |
217 | template<class char_t> |
218 | inline char_t CopyNextWord( char_t it, char_t end, char *pBuffer, size_t length ) |
219 | { |
220 | size_t index = 0; |
221 | it = getNextWord<char_t>( it, end ); |
222 | while( !IsSpaceOrNewLine( *it ) && !isEndOfBuffer( it, end ) ) |
223 | { |
224 | pBuffer[index] = *it ; |
225 | index++; |
226 | if (index == length-1) |
227 | break; |
228 | ++it; |
229 | } |
230 | pBuffer[ index ] = '\0'; |
231 | return it; |
232 | } |
233 | |
234 | /** @brief Get next float from given line |
235 | * @param it set to current position |
236 | * @param end set to end of scratch buffer for readout |
237 | * @param value Separated float value. |
238 | * @return Current-iterator with new position |
239 | */ |
240 | template<class char_t> |
241 | inline char_t getFloat( char_t it, char_t end, ai_real &value ) |
242 | { |
243 | static const size_t BUFFERSIZE = 1024; |
244 | char buffer[ BUFFERSIZE ]; |
245 | it = CopyNextWord<char_t>( it, end, buffer, BUFFERSIZE ); |
246 | value = (ai_real) fast_atof( buffer ); |
247 | |
248 | return it; |
249 | } |
250 | |
251 | /** @brief Will perform a simple tokenize. |
252 | * @param str String to tokenize. |
253 | * @param tokens Array with tokens, will be empty if no token was found. |
254 | * @param delimiters Delimiter for tokenize. |
255 | * @return Number of found token. |
256 | */ |
257 | template<class string_type> |
258 | unsigned int tokenize( const string_type& str, std::vector<string_type>& tokens, |
259 | const string_type& delimiters ) |
260 | { |
261 | // Skip delimiters at beginning. |
262 | typename string_type::size_type lastPos = str.find_first_not_of( delimiters, 0 ); |
263 | |
264 | // Find first "non-delimiter". |
265 | typename string_type::size_type pos = str.find_first_of( delimiters, lastPos ); |
266 | while ( string_type::npos != pos || string_type::npos != lastPos ) |
267 | { |
268 | // Found a token, add it to the vector. |
269 | string_type tmp = str.substr(lastPos, pos - lastPos); |
270 | if ( !tmp.empty() && ' ' != tmp[ 0 ] ) |
271 | tokens.push_back( tmp ); |
272 | |
273 | // Skip delimiters. Note the "not_of" |
274 | lastPos = str.find_first_not_of( delimiters, pos ); |
275 | |
276 | // Find next "non-delimiter" |
277 | pos = str.find_first_of( delimiters, lastPos ); |
278 | } |
279 | |
280 | return static_cast<unsigned int>( tokens.size() ); |
281 | } |
282 | |
283 | template <class string_type> |
284 | string_type trim_whitespaces(string_type str) |
285 | { |
286 | while (!str.empty() && IsSpace(str[0])) str.erase(0); |
287 | while (!str.empty() && IsSpace(str[str.length() - 1])) str.erase(str.length() - 1); |
288 | return str; |
289 | } |
290 | |
291 | template<class T> |
292 | bool hasLineEnd( T it, T end ) { |
293 | bool hasLineEnd( false ); |
294 | while ( !isEndOfBuffer( it, end ) ) { |
295 | it++; |
296 | if ( IsLineEnd( it ) ) { |
297 | hasLineEnd = true; |
298 | break; |
299 | } |
300 | } |
301 | |
302 | return hasLineEnd; |
303 | } |
304 | |
305 | } // Namespace Assimp |
306 | |
307 | #endif // OBJ_TOOLS_H_INC |
308 | |