nuclear@0: /* nuclear@0: Open Asset Import Library (assimp) nuclear@0: ---------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the nuclear@0: following conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: nuclear@0: ---------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file ObjTools.h nuclear@0: * @brief Some helpful templates for text parsing nuclear@0: */ nuclear@0: #ifndef OBJ_TOOLS_H_INC nuclear@0: #define OBJ_TOOLS_H_INC nuclear@0: nuclear@0: #include "fast_atof.h" nuclear@0: nuclear@0: namespace Assimp nuclear@0: { nuclear@0: nuclear@0: /** @brief Returns true, if the last entry of the buffer is reached. nuclear@0: * @param it Iterator of current position. nuclear@0: * @param end Iterator with end of buffer. nuclear@0: * @return true, if the end of the buffer is reached. nuclear@0: */ nuclear@0: template nuclear@0: inline bool isEndOfBuffer( char_t it, char_t end ) nuclear@0: { nuclear@0: if ( it == end ) nuclear@0: { nuclear@0: return true; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: end--; nuclear@0: } nuclear@0: return ( it == end ); nuclear@0: } nuclear@0: nuclear@0: /** @brief Returns true, if token is a space on any supported platform nuclear@0: * @param token Token to search in nuclear@0: * @return true, if token is a space nuclear@0: */ nuclear@0: inline bool isSeparator( char token ) nuclear@0: { nuclear@0: return ( token == ' ' || nuclear@0: token == '\n' || nuclear@0: token == '\f' || nuclear@0: token == '\r' || nuclear@0: token == '\t' ); nuclear@0: } nuclear@0: nuclear@0: /** @brief Returns true, fi token id a new line marking token. nuclear@0: * @param token Token to search in nuclear@0: * @return true, if token is a newline token. nuclear@0: */ nuclear@0: inline bool isNewLine( char token ) nuclear@0: { nuclear@0: return ( token == '\n' || token == '\f' || token == '\r' ); nuclear@0: } nuclear@0: nuclear@0: /** @brief Returns next word separated by a space nuclear@0: * @param pBuffer Pointer to data buffer nuclear@0: * @param pEnd Pointer to end of buffer nuclear@0: * @return Pointer to next space nuclear@0: */ nuclear@0: template nuclear@0: inline Char_T getNextWord( Char_T pBuffer, Char_T pEnd ) nuclear@0: { nuclear@0: while ( !isEndOfBuffer( pBuffer, pEnd ) ) nuclear@0: { nuclear@0: if ( !isSeparator( *pBuffer ) || isNewLine( *pBuffer ) ) nuclear@0: break; nuclear@0: pBuffer++; nuclear@0: } nuclear@0: return pBuffer; nuclear@0: } nuclear@0: nuclear@0: /** @brief Returns ponter a next token nuclear@0: * @param pBuffer Pointer to data buffer nuclear@0: * @param pEnd Pointer to end of buffer nuclear@0: * @return Pointer to next token nuclear@0: */ nuclear@0: template nuclear@0: inline Char_T getNextToken( Char_T pBuffer, Char_T pEnd ) nuclear@0: { nuclear@0: while ( !isEndOfBuffer( pBuffer, pEnd ) ) nuclear@0: { nuclear@0: if ( isSeparator( *pBuffer ) ) nuclear@0: break; nuclear@0: pBuffer++; nuclear@0: } nuclear@0: return getNextWord( pBuffer, pEnd ); nuclear@0: } nuclear@0: nuclear@0: /** @brief Skips a line nuclear@0: * @param it Iterator set to current position nuclear@0: * @param end Iterator set to end of scratch buffer for readout nuclear@0: * @param uiLine Current linenumber in format nuclear@0: * @return Current-iterator with new position nuclear@0: */ nuclear@0: template nuclear@0: inline char_t skipLine( char_t it, char_t end, unsigned int &uiLine ) nuclear@0: { nuclear@0: while ( !isEndOfBuffer( it, end ) && !isNewLine( *it ) ) nuclear@0: ++it; nuclear@0: if ( it != end ) nuclear@0: { nuclear@0: ++it; nuclear@0: ++uiLine; nuclear@0: } nuclear@0: // fix .. from time to time there are spaces at the beginning of a material line nuclear@0: while ( it != end && (*it == '\t' || *it == ' ') ) nuclear@0: ++it; nuclear@0: return it; nuclear@0: } nuclear@0: nuclear@0: /** @brief Get a name from the current line. Preserve space in the middle, nuclear@0: * but trim it at the end. nuclear@0: * @param it set to current position nuclear@0: * @param end set to end of scratch buffer for readout nuclear@0: * @param name Separated name nuclear@0: * @return Current-iterator with new position nuclear@0: */ nuclear@0: template nuclear@0: inline char_t getName( char_t it, char_t end, std::string &name ) nuclear@0: { nuclear@0: name = ""; nuclear@0: it = getNextToken( it, end ); nuclear@0: if ( isEndOfBuffer( it, end ) ) nuclear@0: return end; nuclear@0: nuclear@0: char *pStart = &( *it ); nuclear@0: while ( !isEndOfBuffer( it, end ) && !isNewLine( *it ) ) { nuclear@0: ++it; nuclear@0: } nuclear@0: nuclear@0: while(isEndOfBuffer( it, end ) || isNewLine( *it ) || isSeparator(*it)) { nuclear@0: --it; nuclear@0: } nuclear@0: ++it; nuclear@0: nuclear@0: // Get name nuclear@0: // if there is no name, and the previous char is a separator, come back to start nuclear@0: while (&(*it) < pStart) { nuclear@0: ++it; nuclear@0: } nuclear@0: std::string strName( pStart, &(*it) ); nuclear@0: if ( strName.empty() ) nuclear@0: return it; nuclear@0: else nuclear@0: name = strName; nuclear@0: nuclear@0: return it; nuclear@0: } nuclear@0: nuclear@0: /** @brief Get next word from given line nuclear@0: * @param it set to current position nuclear@0: * @param end set to end of scratch buffer for readout nuclear@0: * @param pBuffer Buffer for next word nuclear@0: * @param length Buffer length nuclear@0: * @return Current-iterator with new position nuclear@0: */ nuclear@0: template nuclear@0: inline char_t CopyNextWord( char_t it, char_t end, char *pBuffer, size_t length ) nuclear@0: { nuclear@0: size_t index = 0; nuclear@0: it = getNextWord( it, end ); nuclear@0: while ( !isSeparator( *it ) && !isEndOfBuffer( it, end ) ) nuclear@0: { nuclear@0: pBuffer[index] = *it ; nuclear@0: index++; nuclear@0: if (index == length-1) nuclear@0: break; nuclear@0: ++it; nuclear@0: } nuclear@0: pBuffer[ index ] = '\0'; nuclear@0: return it; nuclear@0: } nuclear@0: nuclear@0: /** @brief Get next float from given line nuclear@0: * @param it set to current position nuclear@0: * @param end set to end of scratch buffer for readout nuclear@0: * @param value Separated float value. nuclear@0: * @return Current-iterator with new position nuclear@0: */ nuclear@0: template nuclear@0: inline char_t getFloat( char_t it, char_t end, float &value ) nuclear@0: { nuclear@0: static const size_t BUFFERSIZE = 1024; nuclear@0: char buffer[ BUFFERSIZE ]; nuclear@0: it = CopyNextWord( it, end, buffer, BUFFERSIZE ); nuclear@0: value = (float) fast_atof( buffer ); nuclear@0: nuclear@0: return it; nuclear@0: } nuclear@0: nuclear@0: /** @brief Will perform a simple tokenize. nuclear@0: * @param str String to tokenize. nuclear@0: * @param tokens Array with tokens, will be empty if no token was found. nuclear@0: * @param delimiters Delimiter for tokenize. nuclear@0: * @return Number of found token. nuclear@0: */ nuclear@0: template nuclear@0: unsigned int tokenize( const string_type& str, std::vector& tokens, nuclear@0: const string_type& delimiters ) nuclear@0: { nuclear@0: // Skip delimiters at beginning. nuclear@0: typename string_type::size_type lastPos = str.find_first_not_of( delimiters, 0 ); nuclear@0: nuclear@0: // Find first "non-delimiter". nuclear@0: typename string_type::size_type pos = str.find_first_of( delimiters, lastPos ); nuclear@0: while ( string_type::npos != pos || string_type::npos != lastPos ) nuclear@0: { nuclear@0: // Found a token, add it to the vector. nuclear@0: string_type tmp = str.substr(lastPos, pos - lastPos); nuclear@0: if ( !tmp.empty() && ' ' != tmp[ 0 ] ) nuclear@0: tokens.push_back( tmp ); nuclear@0: nuclear@0: // Skip delimiters. Note the "not_of" nuclear@0: lastPos = str.find_first_not_of( delimiters, pos ); nuclear@0: nuclear@0: // Find next "non-delimiter" nuclear@0: pos = str.find_first_of( delimiters, lastPos ); nuclear@0: } nuclear@0: nuclear@0: return static_cast( tokens.size() ); nuclear@0: } nuclear@0: nuclear@0: } // Namespace Assimp nuclear@0: nuclear@0: #endif