diff options
Diffstat (limited to 'src/3rdparty/assimp/code/FBXParser.cpp')
-rw-r--r-- | src/3rdparty/assimp/code/FBXParser.cpp | 1834 |
1 files changed, 964 insertions, 870 deletions
diff --git a/src/3rdparty/assimp/code/FBXParser.cpp b/src/3rdparty/assimp/code/FBXParser.cpp index f6dc2e7e2..beca20b14 100644 --- a/src/3rdparty/assimp/code/FBXParser.cpp +++ b/src/3rdparty/assimp/code/FBXParser.cpp @@ -2,11 +2,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,16 +23,16 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- @@ -41,15 +41,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file FBXParser.cpp * @brief Implementation of the FBX parser and the rudimentary DOM that we use */ -#include "AssimpPCH.h" #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER #ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include <zlib.h> +# include <zlib.h> #else -# include "../contrib/zlib/zlib.h" +# include "../contrib/zlib/zlib.h" #endif @@ -59,6 +58,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ParsingUtils.h" #include "fast_atof.h" +#include "ByteSwapper.h" + +#include <iostream> using namespace Assimp; using namespace Assimp::FBX; @@ -66,53 +68,46 @@ using namespace Assimp::FBX; namespace { - // ------------------------------------------------------------------------------------------------ - // signal parse error, this is always unrecoverable. Throws DeadlyImportError. - void ParseError(const std::string& message, const Token& token) - { - throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token)); - } - - // ------------------------------------------------------------------------------------------------ - void ParseError(const std::string& message, const Element* element = NULL) - { - if(element) { - ParseError(message,element->KeyToken()); - } - throw DeadlyImportError("FBX-Parser " + message); - } - - - // ------------------------------------------------------------------------------------------------ - // print warning, do return - void ParseWarning(const std::string& message, const Token& token) - { - if(DefaultLogger::get()) { - DefaultLogger::get()->warn(Util::AddTokenText("FBX-Parser",message,&token)); - } - } - - // ------------------------------------------------------------------------------------------------ - void ParseWarning(const std::string& message, const Element* element = NULL) - { - if(element) { - ParseWarning(message,element->KeyToken()); - return; - } - if(DefaultLogger::get()) { - DefaultLogger::get()->warn("FBX-Parser: " + message); - } - } - - // ------------------------------------------------------------------------------------------------ - void ParseError(const std::string& message, TokenPtr token) - { - if(token) { - ParseError(message, *token); - } - ParseError(message); - } - + // ------------------------------------------------------------------------------------------------ + // signal parse error, this is always unrecoverable. Throws DeadlyImportError. + AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX; + AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) + { + throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token)); + } + + // ------------------------------------------------------------------------------------------------ + AI_WONT_RETURN void ParseError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX; + AI_WONT_RETURN void ParseError(const std::string& message, const Element* element) + { + if(element) { + ParseError(message,element->KeyToken()); + } + throw DeadlyImportError("FBX-Parser " + message); + } + + + // ------------------------------------------------------------------------------------------------ + void ParseError(const std::string& message, TokenPtr token) + { + if(token) { + ParseError(message, *token); + } + ParseError(message); + } + + // Initially, we did reinterpret_cast, breaking strict aliasing rules. + // This actually caused trouble on Android, so let's be safe this time. + // https://github.com/assimp/assimp/issues/24 + template <typename T> + T SafeParse(const char* data, const char* end) { + // Actual size validation happens during Tokenization so + // this is valid as an assertion. + ai_assert(static_cast<size_t>(end - data) >= sizeof(T)); + T result = static_cast<T>(0); + ::memcpy(&result, data, sizeof(T)); + return result; + } } namespace Assimp { @@ -122,92 +117,99 @@ namespace FBX { Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) { - TokenPtr n = NULL; - do { - n = parser.AdvanceToNextToken(); - if(!n) { - ParseError("unexpected end of file, expected closing bracket",parser.LastToken()); - } - - if (n->Type() == TokenType_DATA) { - tokens.push_back(n); - - n = parser.AdvanceToNextToken(); - if(!n) { - ParseError("unexpected end of file, expected bracket, comma or key",parser.LastToken()); - } + TokenPtr n = NULL; + do { + n = parser.AdvanceToNextToken(); + if(!n) { + ParseError("unexpected end of file, expected closing bracket",parser.LastToken()); + } + + if (n->Type() == TokenType_DATA) { + tokens.push_back(n); + TokenPtr prev = n; + n = parser.AdvanceToNextToken(); + if(!n) { + ParseError("unexpected end of file, expected bracket, comma or key",parser.LastToken()); + } const TokenType ty = n->Type(); - if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) { - ParseError("unexpected token; expected bracket, comma or key",n); + + // some exporters are missing a comma on the next line + if (ty == TokenType_DATA && prev->Type() == TokenType_DATA && (n->Line() == prev->Line() + 1)) { + tokens.push_back(n); + continue; } - } - if (n->Type() == TokenType_OPEN_BRACKET) { - compound.reset(new Scope(parser)); + if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) { + ParseError("unexpected token; expected bracket, comma or key",n); + } + } - // current token should be a TOK_CLOSE_BRACKET - n = parser.CurrentToken(); - ai_assert(n); + if (n->Type() == TokenType_OPEN_BRACKET) { + compound.reset(new Scope(parser)); - if (n->Type() != TokenType_CLOSE_BRACKET) { - ParseError("expected closing bracket",n); - } + // current token should be a TOK_CLOSE_BRACKET + n = parser.CurrentToken(); + ai_assert(n); + + if (n->Type() != TokenType_CLOSE_BRACKET) { + ParseError("expected closing bracket",n); + } - parser.AdvanceToNextToken(); - return; - } - } - while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET); + parser.AdvanceToNextToken(); + return; + } + } + while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET); } // ------------------------------------------------------------------------------------------------ Element::~Element() { - // no need to delete tokens, they are owned by the parser + // no need to delete tokens, they are owned by the parser } // ------------------------------------------------------------------------------------------------ Scope::Scope(Parser& parser,bool topLevel) { - if(!topLevel) { - TokenPtr t = parser.CurrentToken(); - if (t->Type() != TokenType_OPEN_BRACKET) { - ParseError("expected open bracket",t); - } - } - - TokenPtr n = parser.AdvanceToNextToken(); - if(n == NULL) { - ParseError("unexpected end of file"); - } - - // note: empty scopes are allowed - while(n->Type() != TokenType_CLOSE_BRACKET) { - if (n->Type() != TokenType_KEY) { - ParseError("unexpected token, expected TOK_KEY",n); - } - - const std::string& str = n->StringContents(); - elements.insert(ElementMap::value_type(str,new_Element(*n,parser))); - - // Element() should stop at the next Key token (or right after a Close token) - n = parser.CurrentToken(); - if(n == NULL) { - if (topLevel) { - return; - } - ParseError("unexpected end of file",parser.LastToken()); - } - } + if(!topLevel) { + TokenPtr t = parser.CurrentToken(); + if (t->Type() != TokenType_OPEN_BRACKET) { + ParseError("expected open bracket",t); + } + } + + TokenPtr n = parser.AdvanceToNextToken(); + if(n == NULL) { + ParseError("unexpected end of file"); + } + + // note: empty scopes are allowed + while(n->Type() != TokenType_CLOSE_BRACKET) { + if (n->Type() != TokenType_KEY) { + ParseError("unexpected token, expected TOK_KEY",n); + } + + const std::string& str = n->StringContents(); + elements.insert(ElementMap::value_type(str,new_Element(*n,parser))); + + // Element() should stop at the next Key token (or right after a Close token) + n = parser.CurrentToken(); + if(n == NULL) { + if (topLevel) { + return; + } + ParseError("unexpected end of file",parser.LastToken()); + } + } } // ------------------------------------------------------------------------------------------------ Scope::~Scope() { - BOOST_FOREACH(ElementMap::value_type& v, elements) { - delete v.second; - } + for(ElementMap::value_type& v : elements) { + delete v.second; + } } @@ -219,7 +221,7 @@ Parser::Parser (const TokenList& tokens, bool is_binary) , cursor(tokens.begin()) , is_binary(is_binary) { - root.reset(new Scope(*this,true)); + root.reset(new Scope(*this,true)); } @@ -232,250 +234,267 @@ Parser::~Parser() // ------------------------------------------------------------------------------------------------ TokenPtr Parser::AdvanceToNextToken() { - last = current; - if (cursor == tokens.end()) { - current = NULL; - } - else { - current = *cursor++; - } - return current; + last = current; + if (cursor == tokens.end()) { + current = NULL; + } + else { + current = *cursor++; + } + return current; } // ------------------------------------------------------------------------------------------------ TokenPtr Parser::CurrentToken() const { - return current; + return current; } // ------------------------------------------------------------------------------------------------ TokenPtr Parser::LastToken() const { - return last; + return last; } // ------------------------------------------------------------------------------------------------ uint64_t ParseTokenAsID(const Token& t, const char*& err_out) { - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0L; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'L') { - err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; - return 0L; - } - - ai_assert(t.end() - data == 9); - - BE_NCONST uint64_t id = *reinterpret_cast<const uint64_t*>(data+1); - AI_SWAP8(id); - return id; - } - - // XXX: should use size_t here - unsigned int length = static_cast<unsigned int>(t.end() - t.begin()); - ai_assert(length > 0); - - const char* out; - const uint64_t id = strtoul10_64(t.begin(),&out,&length); - if (out > t.end()) { - err_out = "failed to parse ID (text)"; - return 0L; - } - - return id; + err_out = NULL; + + if (t.Type() != TokenType_DATA) { + err_out = "expected TOK_DATA token"; + return 0L; + } + + if(t.IsBinary()) + { + const char* data = t.begin(); + if (data[0] != 'L') { + err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; + return 0L; + } + + BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end()); + AI_SWAP8(id); + return id; + } + + // XXX: should use size_t here + unsigned int length = static_cast<unsigned int>(t.end() - t.begin()); + ai_assert(length > 0); + + const char* out; + const uint64_t id = strtoul10_64(t.begin(),&out,&length); + if (out > t.end()) { + err_out = "failed to parse ID (text)"; + return 0L; + } + + return id; } // ------------------------------------------------------------------------------------------------ size_t ParseTokenAsDim(const Token& t, const char*& err_out) { - // same as ID parsing, except there is a trailing asterisk - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'L') { - err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; - return 0; - } - - ai_assert(t.end() - data == 9); - BE_NCONST uint64_t id = *reinterpret_cast<const uint64_t*>(data+1); - AI_SWAP8(id); - return static_cast<size_t>(id); - } - - if(*t.begin() != '*') { - err_out = "expected asterisk before array dimension"; - return 0; - } - - // XXX: should use size_t here - unsigned int length = static_cast<unsigned int>(t.end() - t.begin()); - if(length == 0) { - err_out = "expected valid integer number after asterisk"; - return 0; - } - - const char* out; - const size_t id = static_cast<size_t>(strtoul10_64(t.begin() + 1,&out,&length)); - if (out > t.end()) { - err_out = "failed to parse ID"; - return 0; - } - - return id; + // same as ID parsing, except there is a trailing asterisk + err_out = NULL; + + if (t.Type() != TokenType_DATA) { + err_out = "expected TOK_DATA token"; + return 0; + } + + if(t.IsBinary()) + { + const char* data = t.begin(); + if (data[0] != 'L') { + err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; + return 0; + } + + BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end()); + AI_SWAP8(id); + return static_cast<size_t>(id); + } + + if(*t.begin() != '*') { + err_out = "expected asterisk before array dimension"; + return 0; + } + + // XXX: should use size_t here + unsigned int length = static_cast<unsigned int>(t.end() - t.begin()); + if(length == 0) { + err_out = "expected valid integer number after asterisk"; + return 0; + } + + const char* out; + const size_t id = static_cast<size_t>(strtoul10_64(t.begin() + 1,&out,&length)); + if (out > t.end()) { + err_out = "failed to parse ID"; + return 0; + } + + return id; } // ------------------------------------------------------------------------------------------------ float ParseTokenAsFloat(const Token& t, const char*& err_out) { - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0.0f; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'F' && data[0] != 'D') { - err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)"; - return 0.0f; - } - - if (data[0] == 'F') { - // Actual size validation happens during Tokenization so - // this is valid as an assertion. - ai_assert(t.end() - data == sizeof(float) + 1); - // Initially, we did reinterpret_cast, breaking strict aliasing rules. - // This actually caused trouble on Android, so let's be safe this time. - // https://github.com/assimp/assimp/issues/24 - - float out_float; - ::memcpy(&out_float, data+1, sizeof(float)); - return out_float; - } - else { - ai_assert(t.end() - data == sizeof(double) + 1); - - // Same - double out_double; - ::memcpy(&out_double, data+1, sizeof(double)); - return static_cast<float>(out_double); - } - } - - // need to copy the input string to a temporary buffer - // first - next in the fbx token stream comes ',', - // which fast_atof could interpret as decimal point. + err_out = NULL; + + if (t.Type() != TokenType_DATA) { + err_out = "expected TOK_DATA token"; + return 0.0f; + } + + if(t.IsBinary()) + { + const char* data = t.begin(); + if (data[0] != 'F' && data[0] != 'D') { + err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)"; + return 0.0f; + } + + if (data[0] == 'F') { + return SafeParse<float>(data+1, t.end()); + } + else { + return static_cast<float>( SafeParse<double>(data+1, t.end()) ); + } + } + + // need to copy the input string to a temporary buffer + // first - next in the fbx token stream comes ',', + // which fast_atof could interpret as decimal point. #define MAX_FLOAT_LENGTH 31 - char temp[MAX_FLOAT_LENGTH + 1]; - const size_t length = static_cast<size_t>(t.end()-t.begin()); - std::copy(t.begin(),t.end(),temp); - temp[std::min(static_cast<size_t>(MAX_FLOAT_LENGTH),length)] = '\0'; + char temp[MAX_FLOAT_LENGTH + 1]; + const size_t length = static_cast<size_t>(t.end()-t.begin()); + std::copy(t.begin(),t.end(),temp); + temp[std::min(static_cast<size_t>(MAX_FLOAT_LENGTH),length)] = '\0'; - return fast_atof(temp); + return fast_atof(temp); } // ------------------------------------------------------------------------------------------------ int ParseTokenAsInt(const Token& t, const char*& err_out) { - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'I') { - err_out = "failed to parse I(nt), unexpected data type (binary)"; - return 0; - } - - ai_assert(t.end() - data == 5); - BE_NCONST int32_t ival = *reinterpret_cast<const int32_t*>(data+1); - AI_SWAP4(ival); - return static_cast<int>(ival); - } - - ai_assert(static_cast<size_t>(t.end() - t.begin()) > 0); - - const char* out; - const int intval = strtol10(t.begin(),&out); - if (out != t.end()) { - err_out = "failed to parse ID"; - return 0; - } - - return intval; + err_out = NULL; + + if (t.Type() != TokenType_DATA) { + err_out = "expected TOK_DATA token"; + return 0; + } + + if(t.IsBinary()) + { + const char* data = t.begin(); + if (data[0] != 'I') { + err_out = "failed to parse I(nt), unexpected data type (binary)"; + return 0; + } + + BE_NCONST int32_t ival = SafeParse<int32_t>(data+1, t.end()); + AI_SWAP4(ival); + return static_cast<int>(ival); + } + + ai_assert(static_cast<size_t>(t.end() - t.begin()) > 0); + + const char* out; + const int intval = strtol10(t.begin(),&out); + if (out != t.end()) { + err_out = "failed to parse ID"; + return 0; + } + + return intval; } // ------------------------------------------------------------------------------------------------ +int64_t ParseTokenAsInt64(const Token& t, const char*& err_out) +{ + err_out = NULL; + + if (t.Type() != TokenType_DATA) { + err_out = "expected TOK_DATA token"; + return 0L; + } + + if (t.IsBinary()) + { + const char* data = t.begin(); + if (data[0] != 'L') { + err_out = "failed to parse Int64, unexpected data type"; + return 0L; + } + + BE_NCONST int64_t id = SafeParse<int64_t>(data + 1, t.end()); + AI_SWAP8(id); + return id; + } + + // XXX: should use size_t here + unsigned int length = static_cast<unsigned int>(t.end() - t.begin()); + ai_assert(length > 0); + + const char* out; + const int64_t id = strtol10_64(t.begin(), &out, &length); + if (out > t.end()) { + err_out = "failed to parse Int64 (text)"; + return 0L; + } + + return id; +} + +// ------------------------------------------------------------------------------------------------ std::string ParseTokenAsString(const Token& t, const char*& err_out) { - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return ""; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'S') { - err_out = "failed to parse S(tring), unexpected data type (binary)"; - return ""; - } - - ai_assert(t.end() - data >= 5); - - // read string length - BE_NCONST int32_t len = *reinterpret_cast<const int32_t*>(data+1); - AI_SWAP4(len); - - ai_assert(t.end() - data == 5 + len); - return std::string(data + 5, len); - } - - const size_t length = static_cast<size_t>(t.end() - t.begin()); - if(length < 2) { - err_out = "token is too short to hold a string"; - return ""; - } - - const char* s = t.begin(), *e = t.end() - 1; - if (*s != '\"' || *e != '\"') { - err_out = "expected double quoted string"; - return ""; - } - - return std::string(s+1,length-2); + err_out = NULL; + + if (t.Type() != TokenType_DATA) { + err_out = "expected TOK_DATA token"; + return ""; + } + + if(t.IsBinary()) + { + const char* data = t.begin(); + if (data[0] != 'S') { + err_out = "failed to parse S(tring), unexpected data type (binary)"; + return ""; + } + + // read string length + BE_NCONST int32_t len = SafeParse<int32_t>(data+1, t.end()); + AI_SWAP4(len); + + ai_assert(t.end() - data == 5 + len); + return std::string(data + 5, len); + } + + const size_t length = static_cast<size_t>(t.end() - t.begin()); + if(length < 2) { + err_out = "token is too short to hold a string"; + return ""; + } + + const char* s = t.begin(), *e = t.end() - 1; + if (*s != '\"' || *e != '\"') { + err_out = "expected double quoted string"; + return ""; + } + + return std::string(s+1,length-2); } @@ -483,107 +502,107 @@ namespace { // ------------------------------------------------------------------------------------------------ // read the type code and element count of a binary data array and stop there -void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uint32_t& count, - const Element& el) +void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uint32_t& count, + const Element& el) { - if (static_cast<size_t>(end-data) < 5) { - ParseError("binary data array is too short, need five (5) bytes for type signature and element count",&el); - } + if (static_cast<size_t>(end-data) < 5) { + ParseError("binary data array is too short, need five (5) bytes for type signature and element count",&el); + } - // data type - type = *data; + // data type + type = *data; - // read number of elements - BE_NCONST uint32_t len = *reinterpret_cast<const uint32_t*>(data+1); - AI_SWAP4(len); + // read number of elements + BE_NCONST uint32_t len = SafeParse<uint32_t>(data+1, end); + AI_SWAP4(len); - count = len; - data += 5; + count = len; + data += 5; } // ------------------------------------------------------------------------------------------------ // read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header) -void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end, - std::vector<char>& buff, - const Element& el) +void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end, + std::vector<char>& buff, + const Element& /*el*/) { - ai_assert(static_cast<size_t>(end-data) >= 4); // runtime check for this happens at tokenization stage - - BE_NCONST uint32_t encmode = *reinterpret_cast<const uint32_t*>(data); - AI_SWAP4(encmode); - data += 4; - - // next comes the compressed length - BE_NCONST uint32_t comp_len = *reinterpret_cast<const uint32_t*>(data); - AI_SWAP4(comp_len); - data += 4; - - ai_assert(data + comp_len == end); - - // determine the length of the uncompressed data by looking at the type signature - uint32_t stride = 0; - switch(type) - { - case 'f': - case 'i': - stride = 4; - break; - - case 'd': - case 'l': - stride = 8; - break; - - default: - ai_assert(false); - }; - - const uint32_t full_length = stride * count; - buff.resize(full_length); - - if(encmode == 0) { - ai_assert(full_length == comp_len); - - // plain data, no compression - std::copy(data, end, buff.begin()); - } - else if(encmode == 1) { - // zlib/deflate, next comes ZIP head (0x78 0x01) - // see http://www.ietf.org/rfc/rfc1950.txt - - z_stream zstream; - zstream.opaque = Z_NULL; - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.data_type = Z_BINARY; - - // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib - inflateInit(&zstream); - - zstream.next_in = reinterpret_cast<Bytef*>( const_cast<char*>(data) ); - zstream.avail_in = comp_len; - - zstream.avail_out = buff.size(); - zstream.next_out = reinterpret_cast<Bytef*>(&*buff.begin()); - const int ret = inflate(&zstream, Z_FINISH); - - if (ret != Z_STREAM_END && ret != Z_OK) { - ParseError("failure decompressing compressed data section"); - } - - // terminate zlib - inflateEnd(&zstream); - } + BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end); + AI_SWAP4(encmode); + data += 4; + + // next comes the compressed length + BE_NCONST uint32_t comp_len = SafeParse<uint32_t>(data, end); + AI_SWAP4(comp_len); + data += 4; + + ai_assert(data + comp_len == end); + + // determine the length of the uncompressed data by looking at the type signature + uint32_t stride = 0; + switch(type) + { + case 'f': + case 'i': + stride = 4; + break; + + case 'd': + case 'l': + stride = 8; + break; + + default: + ai_assert(false); + }; + + const uint32_t full_length = stride * count; + buff.resize(full_length); + + if(encmode == 0) { + ai_assert(full_length == comp_len); + + // plain data, no compression + std::copy(data, end, buff.begin()); + } + else if(encmode == 1) { + // zlib/deflate, next comes ZIP head (0x78 0x01) + // see http://www.ietf.org/rfc/rfc1950.txt + + z_stream zstream; + zstream.opaque = Z_NULL; + zstream.zalloc = Z_NULL; + zstream.zfree = Z_NULL; + zstream.data_type = Z_BINARY; + + // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib + if(Z_OK != inflateInit(&zstream)) { + ParseError("failure initializing zlib"); + } + + zstream.next_in = reinterpret_cast<Bytef*>( const_cast<char*>(data) ); + zstream.avail_in = comp_len; + + zstream.avail_out = buff.size(); + zstream.next_out = reinterpret_cast<Bytef*>(&*buff.begin()); + const int ret = inflate(&zstream, Z_FINISH); + + if (ret != Z_STREAM_END && ret != Z_OK) { + ParseError("failure decompressing compressed data section"); + } + + // terminate zlib + inflateEnd(&zstream); + } #ifdef ASSIMP_BUILD_DEBUG - else { - // runtime check for this happens at tokenization stage - ai_assert(false); - } + else { + // runtime check for this happens at tokenization stage + ai_assert(false); + } #endif - data += comp_len; - ai_assert(data == end); + data += comp_len; + ai_assert(data == end); } } // !anon @@ -593,80 +612,87 @@ void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const cha // read an array of float3 tuples void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el) { - out.clear(); - - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(count % 3 != 0) { - ParseError("number of floats is not a multiple of three (3) (binary)",&el); - } - - if(!count) { - return; - } - - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count3 = count / 3; - out.reserve(count3); - - if (type == 'd') { - const double* d = reinterpret_cast<const double*>(&buff[0]); - for (unsigned int i = 0; i < count3; ++i, d += 3) { - out.push_back(aiVector3D(static_cast<float>(d[0]), - static_cast<float>(d[1]), - static_cast<float>(d[2]))); - } - } - else if (type == 'f') { - const float* f = reinterpret_cast<const float*>(&buff[0]); - for (unsigned int i = 0; i < count3; ++i, f += 3) { - out.push_back(aiVector3D(f[0],f[1],f[2])); - } - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // may throw bad_alloc if the input is rubbish, but this need - // not to be prevented - importing would fail but we wouldn't - // crash since assimp handles this case properly. - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - if (a.Tokens().size() % 3 != 0) { - ParseError("number of floats is not a multiple of three (3)",&el); - } - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - aiVector3D v; - v.x = ParseTokenAsFloat(**it++); - v.y = ParseTokenAsFloat(**it++); - v.z = ParseTokenAsFloat(**it++); - - out.push_back(v); - } + out.resize( 0 ); + + const TokenList& tok = el.Tokens(); + if(tok.empty()) { + ParseError("unexpected empty element",&el); + } + + if(tok[0]->IsBinary()) { + const char* data = tok[0]->begin(), *end = tok[0]->end(); + + char type; + uint32_t count; + ReadBinaryDataArrayHead(data, end, type, count, el); + + if(count % 3 != 0) { + ParseError("number of floats is not a multiple of three (3) (binary)",&el); + } + + if(!count) { + return; + } + + if (type != 'd' && type != 'f') { + ParseError("expected float or double array (binary)",&el); + } + + std::vector<char> buff; + ReadBinaryDataArray(type, count, data, end, buff, el); + + ai_assert(data == end); + ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); + + const uint32_t count3 = count / 3; + out.reserve(count3); + + if (type == 'd') { + const double* d = reinterpret_cast<const double*>(&buff[0]); + for (unsigned int i = 0; i < count3; ++i, d += 3) { + out.push_back(aiVector3D(static_cast<float>(d[0]), + static_cast<float>(d[1]), + static_cast<float>(d[2]))); + } + // for debugging + /*for ( size_t i = 0; i < out.size(); i++ ) { + aiVector3D vec3( out[ i ] ); + std::stringstream stream; + stream << " vec3.x = " << vec3.x << " vec3.y = " << vec3.y << " vec3.z = " << vec3.z << std::endl; + DefaultLogger::get()->info( stream.str() ); + }*/ + } + else if (type == 'f') { + const float* f = reinterpret_cast<const float*>(&buff[0]); + for (unsigned int i = 0; i < count3; ++i, f += 3) { + out.push_back(aiVector3D(f[0],f[1],f[2])); + } + } + + return; + } + + const size_t dim = ParseTokenAsDim(*tok[0]); + + // may throw bad_alloc if the input is rubbish, but this need + // not to be prevented - importing would fail but we wouldn't + // crash since assimp handles this case properly. + out.reserve(dim); + + const Scope& scope = GetRequiredScope(el); + const Element& a = GetRequiredElement(scope,"a",&el); + + if (a.Tokens().size() % 3 != 0) { + ParseError("number of floats is not a multiple of three (3)",&el); + } + for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { + aiVector3D v; + v.x = ParseTokenAsFloat(**it++); + v.y = ParseTokenAsFloat(**it++); + v.z = ParseTokenAsFloat(**it++); + + out.push_back(v); + } } @@ -674,78 +700,78 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el) // read an array of color4 tuples void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el) { - out.clear(); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(count % 4 != 0) { - ParseError("number of floats is not a multiple of four (4) (binary)",&el); - } - - if(!count) { - return; - } - - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count4 = count / 4; - out.reserve(count4); - - if (type == 'd') { - const double* d = reinterpret_cast<const double*>(&buff[0]); - for (unsigned int i = 0; i < count4; ++i, d += 4) { - out.push_back(aiColor4D(static_cast<float>(d[0]), - static_cast<float>(d[1]), - static_cast<float>(d[2]), - static_cast<float>(d[3]))); - } - } - else if (type == 'f') { - const float* f = reinterpret_cast<const float*>(&buff[0]); - for (unsigned int i = 0; i < count4; ++i, f += 4) { - out.push_back(aiColor4D(f[0],f[1],f[2],f[3])); - } - } - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() above - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - if (a.Tokens().size() % 4 != 0) { - ParseError("number of floats is not a multiple of four (4)",&el); - } - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - aiColor4D v; - v.r = ParseTokenAsFloat(**it++); - v.g = ParseTokenAsFloat(**it++); - v.b = ParseTokenAsFloat(**it++); - v.a = ParseTokenAsFloat(**it++); - - out.push_back(v); - } + out.resize( 0 ); + const TokenList& tok = el.Tokens(); + if(tok.empty()) { + ParseError("unexpected empty element",&el); + } + + if(tok[0]->IsBinary()) { + const char* data = tok[0]->begin(), *end = tok[0]->end(); + + char type; + uint32_t count; + ReadBinaryDataArrayHead(data, end, type, count, el); + + if(count % 4 != 0) { + ParseError("number of floats is not a multiple of four (4) (binary)",&el); + } + + if(!count) { + return; + } + + if (type != 'd' && type != 'f') { + ParseError("expected float or double array (binary)",&el); + } + + std::vector<char> buff; + ReadBinaryDataArray(type, count, data, end, buff, el); + + ai_assert(data == end); + ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); + + const uint32_t count4 = count / 4; + out.reserve(count4); + + if (type == 'd') { + const double* d = reinterpret_cast<const double*>(&buff[0]); + for (unsigned int i = 0; i < count4; ++i, d += 4) { + out.push_back(aiColor4D(static_cast<float>(d[0]), + static_cast<float>(d[1]), + static_cast<float>(d[2]), + static_cast<float>(d[3]))); + } + } + else if (type == 'f') { + const float* f = reinterpret_cast<const float*>(&buff[0]); + for (unsigned int i = 0; i < count4; ++i, f += 4) { + out.push_back(aiColor4D(f[0],f[1],f[2],f[3])); + } + } + return; + } + + const size_t dim = ParseTokenAsDim(*tok[0]); + + // see notes in ParseVectorDataArray() above + out.reserve(dim); + + const Scope& scope = GetRequiredScope(el); + const Element& a = GetRequiredElement(scope,"a",&el); + + if (a.Tokens().size() % 4 != 0) { + ParseError("number of floats is not a multiple of four (4)",&el); + } + for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { + aiColor4D v; + v.r = ParseTokenAsFloat(**it++); + v.g = ParseTokenAsFloat(**it++); + v.b = ParseTokenAsFloat(**it++); + v.a = ParseTokenAsFloat(**it++); + + out.push_back(v); + } } @@ -753,75 +779,75 @@ void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el) // read an array of float2 tuples void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el) { - out.clear(); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(count % 2 != 0) { - ParseError("number of floats is not a multiple of two (2) (binary)",&el); - } - - if(!count) { - return; - } - - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count2 = count / 2; - out.reserve(count2); - - if (type == 'd') { - const double* d = reinterpret_cast<const double*>(&buff[0]); - for (unsigned int i = 0; i < count2; ++i, d += 2) { - out.push_back(aiVector2D(static_cast<float>(d[0]), - static_cast<float>(d[1]))); - } - } - else if (type == 'f') { - const float* f = reinterpret_cast<const float*>(&buff[0]); - for (unsigned int i = 0; i < count2; ++i, f += 2) { - out.push_back(aiVector2D(f[0],f[1])); - } - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() above - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - if (a.Tokens().size() % 2 != 0) { - ParseError("number of floats is not a multiple of two (2)",&el); - } - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - aiVector2D v; - v.x = ParseTokenAsFloat(**it++); - v.y = ParseTokenAsFloat(**it++); - - out.push_back(v); - } + out.resize( 0 ); + const TokenList& tok = el.Tokens(); + if(tok.empty()) { + ParseError("unexpected empty element",&el); + } + + if(tok[0]->IsBinary()) { + const char* data = tok[0]->begin(), *end = tok[0]->end(); + + char type; + uint32_t count; + ReadBinaryDataArrayHead(data, end, type, count, el); + + if(count % 2 != 0) { + ParseError("number of floats is not a multiple of two (2) (binary)",&el); + } + + if(!count) { + return; + } + + if (type != 'd' && type != 'f') { + ParseError("expected float or double array (binary)",&el); + } + + std::vector<char> buff; + ReadBinaryDataArray(type, count, data, end, buff, el); + + ai_assert(data == end); + ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); + + const uint32_t count2 = count / 2; + out.reserve(count2); + + if (type == 'd') { + const double* d = reinterpret_cast<const double*>(&buff[0]); + for (unsigned int i = 0; i < count2; ++i, d += 2) { + out.push_back(aiVector2D(static_cast<float>(d[0]), + static_cast<float>(d[1]))); + } + } + else if (type == 'f') { + const float* f = reinterpret_cast<const float*>(&buff[0]); + for (unsigned int i = 0; i < count2; ++i, f += 2) { + out.push_back(aiVector2D(f[0],f[1])); + } + } + + return; + } + + const size_t dim = ParseTokenAsDim(*tok[0]); + + // see notes in ParseVectorDataArray() above + out.reserve(dim); + + const Scope& scope = GetRequiredScope(el); + const Element& a = GetRequiredElement(scope,"a",&el); + + if (a.Tokens().size() % 2 != 0) { + ParseError("number of floats is not a multiple of two (2)",&el); + } + for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { + aiVector2D v; + v.x = ParseTokenAsFloat(**it++); + v.y = ParseTokenAsFloat(**it++); + + out.push_back(v); + } } @@ -829,57 +855,57 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el) // read an array of ints void ParseVectorDataArray(std::vector<int>& out, const Element& el) { - out.clear(); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } + out.resize( 0 ); + const TokenList& tok = el.Tokens(); + if(tok.empty()) { + ParseError("unexpected empty element",&el); + } - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); + if(tok[0]->IsBinary()) { + const char* data = tok[0]->begin(), *end = tok[0]->end(); - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); + char type; + uint32_t count; + ReadBinaryDataArrayHead(data, end, type, count, el); - if(!count) { - return; - } + if(!count) { + return; + } - if (type != 'i') { - ParseError("expected int array (binary)",&el); - } + if (type != 'i') { + ParseError("expected int array (binary)",&el); + } - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); + std::vector<char> buff; + ReadBinaryDataArray(type, count, data, end, buff, el); - ai_assert(data == end); - ai_assert(buff.size() == count * 4); + ai_assert(data == end); + ai_assert(buff.size() == count * 4); - out.reserve(count); + out.reserve(count); - const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - BE_NCONST int32_t val = *ip; - AI_SWAP4(val); - out.push_back(val); - } + const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]); + for (unsigned int i = 0; i < count; ++i, ++ip) { + BE_NCONST int32_t val = *ip; + AI_SWAP4(val); + out.push_back(val); + } - return; - } + return; + } - const size_t dim = ParseTokenAsDim(*tok[0]); + const size_t dim = ParseTokenAsDim(*tok[0]); - // see notes in ParseVectorDataArray() - out.reserve(dim); + // see notes in ParseVectorDataArray() + out.reserve(dim); - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); + const Scope& scope = GetRequiredScope(el); + const Element& a = GetRequiredElement(scope,"a",&el); - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const int ival = ParseTokenAsInt(**it++); - out.push_back(ival); - } + for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { + const int ival = ParseTokenAsInt(**it++); + out.push_back(ival); + } } @@ -887,223 +913,280 @@ void ParseVectorDataArray(std::vector<int>& out, const Element& el) // read an array of floats void ParseVectorDataArray(std::vector<float>& out, const Element& el) { - out.clear(); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } + out.resize( 0 ); + const TokenList& tok = el.Tokens(); + if(tok.empty()) { + ParseError("unexpected empty element",&el); + } + + if(tok[0]->IsBinary()) { + const char* data = tok[0]->begin(), *end = tok[0]->end(); + + char type; + uint32_t count; + ReadBinaryDataArrayHead(data, end, type, count, el); + + if(!count) { + return; + } + + if (type != 'd' && type != 'f') { + ParseError("expected float or double array (binary)",&el); + } + + std::vector<char> buff; + ReadBinaryDataArray(type, count, data, end, buff, el); + + ai_assert(data == end); + ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); + + if (type == 'd') { + const double* d = reinterpret_cast<const double*>(&buff[0]); + for (unsigned int i = 0; i < count; ++i, ++d) { + out.push_back(static_cast<float>(*d)); + } + } + else if (type == 'f') { + const float* f = reinterpret_cast<const float*>(&buff[0]); + for (unsigned int i = 0; i < count; ++i, ++f) { + out.push_back(*f); + } + } + + return; + } + + const size_t dim = ParseTokenAsDim(*tok[0]); + + // see notes in ParseVectorDataArray() + out.reserve(dim); + + const Scope& scope = GetRequiredScope(el); + const Element& a = GetRequiredElement(scope,"a",&el); + + for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { + const float ival = ParseTokenAsFloat(**it++); + out.push_back(ival); + } +} + + +// ------------------------------------------------------------------------------------------------ +// read an array of uints +void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) +{ + out.resize( 0 ); + const TokenList& tok = el.Tokens(); + if(tok.empty()) { + ParseError("unexpected empty element",&el); + } - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); + if(tok[0]->IsBinary()) { + const char* data = tok[0]->begin(), *end = tok[0]->end(); - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); + char type; + uint32_t count; + ReadBinaryDataArrayHead(data, end, type, count, el); - if(!count) { - return; - } + if(!count) { + return; + } - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } + if (type != 'i') { + ParseError("expected (u)int array (binary)",&el); + } - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); + std::vector<char> buff; + ReadBinaryDataArray(type, count, data, end, buff, el); - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); + ai_assert(data == end); + ai_assert(buff.size() == count * 4); - if (type == 'd') { - const double* d = reinterpret_cast<const double*>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++d) { - out.push_back(static_cast<float>(*d)); - } - } - else if (type == 'f') { - const float* f = reinterpret_cast<const float*>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++f) { - out.push_back(*f); - } - } + out.reserve(count); + + const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]); + for (unsigned int i = 0; i < count; ++i, ++ip) { + BE_NCONST int32_t val = *ip; + if(val < 0) { + ParseError("encountered negative integer index (binary)"); + } - return; - } + AI_SWAP4(val); + out.push_back(val); + } - const size_t dim = ParseTokenAsDim(*tok[0]); + return; + } - // see notes in ParseVectorDataArray() - out.reserve(dim); + const size_t dim = ParseTokenAsDim(*tok[0]); - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); + // see notes in ParseVectorDataArray() + out.reserve(dim); - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const float ival = ParseTokenAsFloat(**it++); - out.push_back(ival); - } + const Scope& scope = GetRequiredScope(el); + const Element& a = GetRequiredElement(scope,"a",&el); + + for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { + const int ival = ParseTokenAsInt(**it++); + if(ival < 0) { + ParseError("encountered negative integer index"); + } + out.push_back(static_cast<unsigned int>(ival)); + } } // ------------------------------------------------------------------------------------------------ -// read an array of uints -void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) +// read an array of uint64_ts +void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el) { - out.clear(); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } + out.resize( 0 ); + const TokenList& tok = el.Tokens(); + if(tok.empty()) { + ParseError("unexpected empty element",&el); + } - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); + if(tok[0]->IsBinary()) { + const char* data = tok[0]->begin(), *end = tok[0]->end(); - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); + char type; + uint32_t count; + ReadBinaryDataArrayHead(data, end, type, count, el); - if(!count) { - return; - } + if(!count) { + return; + } - if (type != 'i') { - ParseError("expected (u)int array (binary)",&el); - } + if (type != 'l') { + ParseError("expected long array (binary)",&el); + } - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); + std::vector<char> buff; + ReadBinaryDataArray(type, count, data, end, buff, el); - ai_assert(data == end); - ai_assert(buff.size() == count * 4); + ai_assert(data == end); + ai_assert(buff.size() == count * 8); - out.reserve(count); + out.reserve(count); - const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - BE_NCONST int32_t val = *ip; - if(val < 0) { - ParseError("encountered negative integer index (binary)"); - } + const uint64_t* ip = reinterpret_cast<const uint64_t*>(&buff[0]); + for (unsigned int i = 0; i < count; ++i, ++ip) { + BE_NCONST uint64_t val = *ip; + AI_SWAP8(val); + out.push_back(val); + } - AI_SWAP4(val); - out.push_back(val); - } + return; + } - return; - } + const size_t dim = ParseTokenAsDim(*tok[0]); - const size_t dim = ParseTokenAsDim(*tok[0]); + // see notes in ParseVectorDataArray() + out.reserve(dim); - // see notes in ParseVectorDataArray() - out.reserve(dim); + const Scope& scope = GetRequiredScope(el); + const Element& a = GetRequiredElement(scope,"a",&el); - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); + for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { + const uint64_t ival = ParseTokenAsID(**it++); - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const int ival = ParseTokenAsInt(**it++); - if(ival < 0) { - ParseError("encountered negative integer index"); - } - out.push_back(static_cast<unsigned int>(ival)); - } + out.push_back(ival); + } } - // ------------------------------------------------------------------------------------------------ -// read an array of uint64_ts -void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el) +// read an array of int64_ts +void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el) { - out.clear(); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } + out.resize( 0 ); + const TokenList& tok = el.Tokens(); + if (tok.empty()) { + ParseError("unexpected empty element", &el); + } - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); + if (tok[0]->IsBinary()) { + const char* data = tok[0]->begin(), *end = tok[0]->end(); - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); + char type; + uint32_t count; + ReadBinaryDataArrayHead(data, end, type, count, el); - if(!count) { - return; - } + if (!count) { + return; + } - if (type != 'l') { - ParseError("expected long array (binary)",&el); - } + if (type != 'l') { + ParseError("expected long array (binary)", &el); + } - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); + std::vector<char> buff; + ReadBinaryDataArray(type, count, data, end, buff, el); - ai_assert(data == end); - ai_assert(buff.size() == count * 8); + ai_assert(data == end); + ai_assert(buff.size() == count * 8); - out.reserve(count); + out.reserve(count); - const uint64_t* ip = reinterpret_cast<const uint64_t*>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - BE_NCONST uint64_t val = *ip; - AI_SWAP8(val); - out.push_back(val); - } + const int64_t* ip = reinterpret_cast<const int64_t*>(&buff[0]); + for (unsigned int i = 0; i < count; ++i, ++ip) { + BE_NCONST int64_t val = *ip; + AI_SWAP8(val); + out.push_back(val); + } - return; - } + return; + } - const size_t dim = ParseTokenAsDim(*tok[0]); + const size_t dim = ParseTokenAsDim(*tok[0]); - // see notes in ParseVectorDataArray() - out.reserve(dim); + // see notes in ParseVectorDataArray() + out.reserve(dim); - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); + const Scope& scope = GetRequiredScope(el); + const Element& a = GetRequiredElement(scope, "a", &el); - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const uint64_t ival = ParseTokenAsID(**it++); - - out.push_back(ival); - } -} + for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end;) { + const int64_t ival = ParseTokenAsInt64(**it++); + out.push_back(ival); + } +} // ------------------------------------------------------------------------------------------------ aiMatrix4x4 ReadMatrix(const Element& element) { - std::vector<float> values; - ParseVectorDataArray(values,element); + std::vector<float> values; + ParseVectorDataArray(values,element); - if(values.size() != 16) { - ParseError("expected 16 matrix elements"); - } + if(values.size() != 16) { + ParseError("expected 16 matrix elements"); + } - aiMatrix4x4 result; + aiMatrix4x4 result; - result.a1 = values[0]; - result.a2 = values[1]; - result.a3 = values[2]; - result.a4 = values[3]; + result.a1 = values[0]; + result.a2 = values[1]; + result.a3 = values[2]; + result.a4 = values[3]; - result.b1 = values[4]; - result.b2 = values[5]; - result.b3 = values[6]; - result.b4 = values[7]; + result.b1 = values[4]; + result.b2 = values[5]; + result.b3 = values[6]; + result.b4 = values[7]; - result.c1 = values[8]; - result.c2 = values[9]; - result.c3 = values[10]; - result.c4 = values[11]; + result.c1 = values[8]; + result.c2 = values[9]; + result.c3 = values[10]; + result.c4 = values[11]; - result.d1 = values[12]; - result.d2 = values[13]; - result.d3 = values[14]; - result.d4 = values[15]; + result.d1 = values[12]; + result.d2 = values[13]; + result.d3 = values[14]; + result.d4 = values[15]; - result.Transpose(); - return result; + result.Transpose(); + return result; } @@ -1111,24 +1194,24 @@ aiMatrix4x4 ReadMatrix(const Element& element) // wrapper around ParseTokenAsString() with ParseError handling std::string ParseTokenAsString(const Token& t) { - const char* err; - const std::string& i = ParseTokenAsString(t,err); - if(err) { - ParseError(err,t); - } - return i; + const char* err; + const std::string& i = ParseTokenAsString(t,err); + if(err) { + ParseError(err,t); + } + return i; } // ------------------------------------------------------------------------------------------------ // extract a required element from a scope, abort if the element cannot be found -const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/) +const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/) { - const Element* el = sc[index]; - if(!el) { - ParseError("did not find required element \"" + index + "\"",element); - } - return *el; + const Element* el = sc[index]; + if(!el) { + ParseError("did not find required element \"" + index + "\"",element); + } + return *el; } @@ -1136,12 +1219,12 @@ const Element& GetRequiredElement(const Scope& sc, const std::string& index, con // extract required compound scope const Scope& GetRequiredScope(const Element& el) { - const Scope* const s = el.Compound(); - if(!s) { - ParseError("expected compound scope",&el); - } + const Scope* const s = el.Compound(); + if(!s) { + ParseError("expected compound scope",&el); + } - return *s; + return *s; } @@ -1149,25 +1232,25 @@ const Scope& GetRequiredScope(const Element& el) // get token at a particular index const Token& GetRequiredToken(const Element& el, unsigned int index) { - const TokenList& t = el.Tokens(); - if(index >= t.size()) { - ParseError(Formatter::format( "missing token at index " ) << index,&el); - } + const TokenList& t = el.Tokens(); + if(index >= t.size()) { + ParseError(Formatter::format( "missing token at index " ) << index,&el); + } - return *t[index]; + return *t[index]; } // ------------------------------------------------------------------------------------------------ // wrapper around ParseTokenAsID() with ParseError handling -uint64_t ParseTokenAsID(const Token& t) +uint64_t ParseTokenAsID(const Token& t) { - const char* err; - const uint64_t i = ParseTokenAsID(t,err); - if(err) { - ParseError(err,t); - } - return i; + const char* err; + const uint64_t i = ParseTokenAsID(t,err); + if(err) { + ParseError(err,t); + } + return i; } @@ -1175,12 +1258,12 @@ uint64_t ParseTokenAsID(const Token& t) // wrapper around ParseTokenAsDim() with ParseError handling size_t ParseTokenAsDim(const Token& t) { - const char* err; - const size_t i = ParseTokenAsDim(t,err); - if(err) { - ParseError(err,t); - } - return i; + const char* err; + const size_t i = ParseTokenAsDim(t,err); + if(err) { + ParseError(err,t); + } + return i; } @@ -1188,12 +1271,12 @@ size_t ParseTokenAsDim(const Token& t) // wrapper around ParseTokenAsFloat() with ParseError handling float ParseTokenAsFloat(const Token& t) { - const char* err; - const float i = ParseTokenAsFloat(t,err); - if(err) { - ParseError(err,t); - } - return i; + const char* err; + const float i = ParseTokenAsFloat(t,err); + if(err) { + ParseError(err,t); + } + return i; } @@ -1201,18 +1284,29 @@ float ParseTokenAsFloat(const Token& t) // wrapper around ParseTokenAsInt() with ParseError handling int ParseTokenAsInt(const Token& t) { - const char* err; - const int i = ParseTokenAsInt(t,err); - if(err) { - ParseError(err,t); - } - return i; + const char* err; + const int i = ParseTokenAsInt(t,err); + if(err) { + ParseError(err,t); + } + return i; } +// ------------------------------------------------------------------------------------------------ +// wrapper around ParseTokenAsInt64() with ParseError handling +int64_t ParseTokenAsInt64(const Token& t) +{ + const char* err; + const int64_t i = ParseTokenAsInt64(t, err); + if (err) { + ParseError(err, t); + } + return i; +} + } // !FBX } // !Assimp #endif - |