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>
isEndOfBuffer(char_t it,char_t end)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>
getNextWord(Char_T pBuffer,Char_T pEnd)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>
getNextToken(Char_T pBuffer,Char_T pEnd)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>
skipLine(char_t it,char_t end,unsigned int & uiLine)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>
getName(char_t it,char_t end,std::string & name)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>
getNameNoSpace(char_t it,char_t end,std::string & name)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>
CopyNextWord(char_t it,char_t end,char * pBuffer,size_t length)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>
getFloat(char_t it,char_t end,ai_real & value)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>
tokenize(const string_type & str,std::vector<string_type> & tokens,const string_type & delimiters)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>
trim_whitespaces(string_type str)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>
hasLineEnd(T it,T end)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