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