vrshoot
view libs/assimp/FBXParser.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line source
1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
5 Copyright (c) 2006-2012, assimp team
6 All rights reserved.
8 Redistribution and use of this software in source and binary forms,
9 with or without modification, are permitted provided that the
10 following conditions are met:
12 * Redistributions of source code must retain the above
13 copyright notice, this list of conditions and the
14 following disclaimer.
16 * Redistributions in binary form must reproduce the above
17 copyright notice, this list of conditions and the
18 following disclaimer in the documentation and/or other
19 materials provided with the distribution.
21 * Neither the name of the assimp team, nor the names of its
22 contributors may be used to endorse or promote products
23 derived from this software without specific prior
24 written permission of the assimp team.
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 ----------------------------------------------------------------------
39 */
41 /** @file FBXParser.cpp
42 * @brief Implementation of the FBX parser and the rudimentary DOM that we use
43 */
44 #include "AssimpPCH.h"
46 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
49 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
50 # include <zlib.h>
51 #else
52 # include "../contrib/zlib/zlib.h"
53 #endif
56 #include "FBXTokenizer.h"
57 #include "FBXParser.h"
58 #include "FBXUtil.h"
60 #include "ParsingUtils.h"
61 #include "fast_atof.h"
63 using namespace Assimp;
64 using namespace Assimp::FBX;
66 namespace {
69 // ------------------------------------------------------------------------------------------------
70 // signal parse error, this is always unrecoverable. Throws DeadlyImportError.
71 void ParseError(const std::string& message, const Token& token)
72 {
73 throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token));
74 }
76 // ------------------------------------------------------------------------------------------------
77 void ParseError(const std::string& message, const Element* element = NULL)
78 {
79 if(element) {
80 ParseError(message,element->KeyToken());
81 }
82 throw DeadlyImportError("FBX-Parser " + message);
83 }
86 // ------------------------------------------------------------------------------------------------
87 // print warning, do return
88 void ParseWarning(const std::string& message, const Token& token)
89 {
90 if(DefaultLogger::get()) {
91 DefaultLogger::get()->warn(Util::AddTokenText("FBX-Parser",message,&token));
92 }
93 }
95 // ------------------------------------------------------------------------------------------------
96 void ParseWarning(const std::string& message, const Element* element = NULL)
97 {
98 if(element) {
99 ParseWarning(message,element->KeyToken());
100 return;
101 }
102 if(DefaultLogger::get()) {
103 DefaultLogger::get()->warn("FBX-Parser: " + message);
104 }
105 }
107 // ------------------------------------------------------------------------------------------------
108 void ParseError(const std::string& message, TokenPtr token)
109 {
110 if(token) {
111 ParseError(message, *token);
112 }
113 ParseError(message);
114 }
116 }
118 namespace Assimp {
119 namespace FBX {
121 // ------------------------------------------------------------------------------------------------
122 Element::Element(const Token& key_token, Parser& parser)
123 : key_token(key_token)
124 {
125 TokenPtr n = NULL;
126 do {
127 n = parser.AdvanceToNextToken();
128 if(!n) {
129 ParseError("unexpected end of file, expected closing bracket",parser.LastToken());
130 }
132 if (n->Type() == TokenType_DATA) {
133 tokens.push_back(n);
135 n = parser.AdvanceToNextToken();
136 if(!n) {
137 ParseError("unexpected end of file, expected bracket, comma or key",parser.LastToken());
138 }
140 const TokenType ty = n->Type();
141 if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) {
142 ParseError("unexpected token; expected bracket, comma or key",n);
143 }
144 }
146 if (n->Type() == TokenType_OPEN_BRACKET) {
147 compound.reset(new Scope(parser));
149 // current token should be a TOK_CLOSE_BRACKET
150 n = parser.CurrentToken();
151 ai_assert(n);
153 if (n->Type() != TokenType_CLOSE_BRACKET) {
154 ParseError("expected closing bracket",n);
155 }
157 parser.AdvanceToNextToken();
158 return;
159 }
160 }
161 while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
162 }
164 // ------------------------------------------------------------------------------------------------
165 Element::~Element()
166 {
167 // no need to delete tokens, they are owned by the parser
168 }
170 // ------------------------------------------------------------------------------------------------
171 Scope::Scope(Parser& parser,bool topLevel)
172 {
173 if(!topLevel) {
174 TokenPtr t = parser.CurrentToken();
175 if (t->Type() != TokenType_OPEN_BRACKET) {
176 ParseError("expected open bracket",t);
177 }
178 }
180 TokenPtr n = parser.AdvanceToNextToken();
181 if(n == NULL) {
182 ParseError("unexpected end of file");
183 }
185 // note: empty scopes are allowed
186 while(n->Type() != TokenType_CLOSE_BRACKET) {
187 if (n->Type() != TokenType_KEY) {
188 ParseError("unexpected token, expected TOK_KEY",n);
189 }
191 const std::string& str = n->StringContents();
192 elements.insert(ElementMap::value_type(str,new_Element(*n,parser)));
194 // Element() should stop at the next Key token (or right after a Close token)
195 n = parser.CurrentToken();
196 if(n == NULL) {
197 if (topLevel) {
198 return;
199 }
200 ParseError("unexpected end of file",parser.LastToken());
201 }
202 }
203 }
205 // ------------------------------------------------------------------------------------------------
206 Scope::~Scope()
207 {
208 BOOST_FOREACH(ElementMap::value_type& v, elements) {
209 delete v.second;
210 }
211 }
214 // ------------------------------------------------------------------------------------------------
215 Parser::Parser (const TokenList& tokens, bool is_binary)
216 : tokens(tokens)
217 , last()
218 , current()
219 , cursor(tokens.begin())
220 , is_binary(is_binary)
221 {
222 root.reset(new Scope(*this,true));
223 }
226 // ------------------------------------------------------------------------------------------------
227 Parser::~Parser()
228 {
229 }
232 // ------------------------------------------------------------------------------------------------
233 TokenPtr Parser::AdvanceToNextToken()
234 {
235 last = current;
236 if (cursor == tokens.end()) {
237 current = NULL;
238 }
239 else {
240 current = *cursor++;
241 }
242 return current;
243 }
246 // ------------------------------------------------------------------------------------------------
247 TokenPtr Parser::CurrentToken() const
248 {
249 return current;
250 }
253 // ------------------------------------------------------------------------------------------------
254 TokenPtr Parser::LastToken() const
255 {
256 return last;
257 }
260 // ------------------------------------------------------------------------------------------------
261 uint64_t ParseTokenAsID(const Token& t, const char*& err_out)
262 {
263 err_out = NULL;
265 if (t.Type() != TokenType_DATA) {
266 err_out = "expected TOK_DATA token";
267 return 0L;
268 }
270 if(t.IsBinary())
271 {
272 const char* data = t.begin();
273 if (data[0] != 'L') {
274 err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
275 return 0L;
276 }
278 ai_assert(t.end() - data == 9);
280 BE_NCONST uint64_t id = *reinterpret_cast<const uint64_t*>(data+1);
281 AI_SWAP8(id);
282 return id;
283 }
285 // XXX: should use size_t here
286 unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
287 ai_assert(length > 0);
289 const char* out;
290 const uint64_t id = strtoul10_64(t.begin(),&out,&length);
291 if (out > t.end()) {
292 err_out = "failed to parse ID (text)";
293 return 0L;
294 }
296 return id;
297 }
300 // ------------------------------------------------------------------------------------------------
301 size_t ParseTokenAsDim(const Token& t, const char*& err_out)
302 {
303 // same as ID parsing, except there is a trailing asterisk
304 err_out = NULL;
306 if (t.Type() != TokenType_DATA) {
307 err_out = "expected TOK_DATA token";
308 return 0;
309 }
311 if(t.IsBinary())
312 {
313 const char* data = t.begin();
314 if (data[0] != 'L') {
315 err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
316 return 0;
317 }
319 ai_assert(t.end() - data == 9);
320 BE_NCONST uint64_t id = *reinterpret_cast<const uint64_t*>(data+1);
321 AI_SWAP8(id);
322 return static_cast<size_t>(id);
323 }
325 if(*t.begin() != '*') {
326 err_out = "expected asterisk before array dimension";
327 return 0;
328 }
330 // XXX: should use size_t here
331 unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
332 if(length == 0) {
333 err_out = "expected valid integer number after asterisk";
334 return 0;
335 }
337 const char* out;
338 const size_t id = static_cast<size_t>(strtoul10_64(t.begin() + 1,&out,&length));
339 if (out > t.end()) {
340 err_out = "failed to parse ID";
341 return 0;
342 }
344 return id;
345 }
348 // ------------------------------------------------------------------------------------------------
349 float ParseTokenAsFloat(const Token& t, const char*& err_out)
350 {
351 err_out = NULL;
353 if (t.Type() != TokenType_DATA) {
354 err_out = "expected TOK_DATA token";
355 return 0.0f;
356 }
358 if(t.IsBinary())
359 {
360 const char* data = t.begin();
361 if (data[0] != 'F' && data[0] != 'D') {
362 err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)";
363 return 0.0f;
364 }
366 if (data[0] == 'F') {
367 ai_assert(t.end() - data == 5);
368 // no byte swapping needed for ieee floats
369 float res;
370 memcpy(&res, data + 1, sizeof res);
371 return res;
372 }
373 else {
374 ai_assert(t.end() - data == 9);
375 // no byte swapping needed for ieee floats
376 double res;
377 memcpy(&res, data + 1, sizeof res);
378 return (float)res;
379 }
380 }
382 // need to copy the input string to a temporary buffer
383 // first - next in the fbx token stream comes ',',
384 // which fast_atof could interpret as decimal point.
385 #define MAX_FLOAT_LENGTH 31
386 char temp[MAX_FLOAT_LENGTH + 1];
387 const size_t length = static_cast<size_t>(t.end()-t.begin());
388 std::copy(t.begin(),t.end(),temp);
389 temp[std::min(static_cast<size_t>(MAX_FLOAT_LENGTH),length)] = '\0';
391 return fast_atof(temp);
392 }
395 // ------------------------------------------------------------------------------------------------
396 int ParseTokenAsInt(const Token& t, const char*& err_out)
397 {
398 err_out = NULL;
400 if (t.Type() != TokenType_DATA) {
401 err_out = "expected TOK_DATA token";
402 return 0;
403 }
405 if(t.IsBinary())
406 {
407 const char* data = t.begin();
408 if (data[0] != 'I') {
409 err_out = "failed to parse I(nt), unexpected data type (binary)";
410 return 0;
411 }
413 ai_assert(t.end() - data == 5);
414 BE_NCONST int32_t ival = *reinterpret_cast<const int32_t*>(data+1);
415 AI_SWAP4(ival);
416 return static_cast<int>(ival);
417 }
419 ai_assert(static_cast<size_t>(t.end() - t.begin()) > 0);
421 const char* out;
422 const int intval = strtol10(t.begin(),&out);
423 if (out != t.end()) {
424 err_out = "failed to parse ID";
425 return 0;
426 }
428 return intval;
429 }
432 // ------------------------------------------------------------------------------------------------
433 std::string ParseTokenAsString(const Token& t, const char*& err_out)
434 {
435 err_out = NULL;
437 if (t.Type() != TokenType_DATA) {
438 err_out = "expected TOK_DATA token";
439 return "";
440 }
442 if(t.IsBinary())
443 {
444 const char* data = t.begin();
445 if (data[0] != 'S') {
446 err_out = "failed to parse S(tring), unexpected data type (binary)";
447 return "";
448 }
450 ai_assert(t.end() - data >= 5);
452 // read string length
453 BE_NCONST int32_t len = *reinterpret_cast<const int32_t*>(data+1);
454 AI_SWAP4(len);
456 ai_assert(t.end() - data == 5 + len);
457 return std::string(data + 5, len);
458 }
460 const size_t length = static_cast<size_t>(t.end() - t.begin());
461 if(length < 2) {
462 err_out = "token is too short to hold a string";
463 return "";
464 }
466 const char* s = t.begin(), *e = t.end() - 1;
467 if (*s != '\"' || *e != '\"') {
468 err_out = "expected double quoted string";
469 return "";
470 }
472 return std::string(s+1,length-2);
473 }
476 namespace {
478 // ------------------------------------------------------------------------------------------------
479 // read the type code and element count of a binary data array and stop there
480 void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uint32_t& count,
481 const Element& el)
482 {
483 if (static_cast<size_t>(end-data) < 5) {
484 ParseError("binary data array is too short, need five (5) bytes for type signature and element count",&el);
485 }
487 // data type
488 type = *data;
490 // read number of elements
491 BE_NCONST uint32_t len = *reinterpret_cast<const uint32_t*>(data+1);
492 AI_SWAP4(len);
494 count = len;
495 data += 5;
496 }
499 // ------------------------------------------------------------------------------------------------
500 // read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
501 void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end,
502 std::vector<char>& buff,
503 const Element& el)
504 {
505 ai_assert(static_cast<size_t>(end-data) >= 4); // runtime check for this happens at tokenization stage
507 BE_NCONST uint32_t encmode = *reinterpret_cast<const uint32_t*>(data);
508 AI_SWAP4(encmode);
509 data += 4;
511 // next comes the compressed length
512 BE_NCONST uint32_t comp_len = *reinterpret_cast<const uint32_t*>(data);
513 AI_SWAP4(comp_len);
514 data += 4;
516 ai_assert(data + comp_len == end);
518 // determine the length of the uncompressed data by looking at the type signature
519 uint32_t stride;
520 switch(type)
521 {
522 case 'f':
523 case 'i':
524 stride = 4;
525 break;
527 case 'd':
528 case 'l':
529 stride = 8;
530 break;
532 default:
533 ai_assert(false);
534 };
536 const uint32_t full_length = stride * count;
537 buff.resize(full_length);
539 if(encmode == 0) {
540 ai_assert(full_length == comp_len);
542 // plain data, no compression
543 std::copy(data, end, buff.begin());
544 }
545 else if(encmode == 1) {
546 // zlib/deflate, next comes ZIP head (0x78 0x01)
547 // see http://www.ietf.org/rfc/rfc1950.txt
549 z_stream zstream;
550 zstream.opaque = Z_NULL;
551 zstream.zalloc = Z_NULL;
552 zstream.zfree = Z_NULL;
553 zstream.data_type = Z_BINARY;
555 // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
556 inflateInit(&zstream);
558 zstream.next_in = reinterpret_cast<Bytef*>( const_cast<char*>(data) );
559 zstream.avail_in = comp_len;
561 zstream.avail_out = buff.size();
562 zstream.next_out = reinterpret_cast<Bytef*>(&*buff.begin());
563 const int ret = inflate(&zstream, Z_FINISH);
565 if (ret != Z_STREAM_END && ret != Z_OK) {
566 ParseError("failure decompressing compressed data section");
567 }
569 // terminate zlib
570 inflateEnd(&zstream);
571 }
572 #ifdef _DEBUG
573 else {
574 // runtime check for this happens at tokenization stage
575 ai_assert(false);
576 }
577 #endif
579 data += comp_len;
580 ai_assert(data == end);
581 }
583 } // !anon
586 // ------------------------------------------------------------------------------------------------
587 // read an array of float3 tuples
588 void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
589 {
590 out.clear();
592 const TokenList& tok = el.Tokens();
593 if(tok.empty()) {
594 ParseError("unexpected empty element",&el);
595 }
597 if(tok[0]->IsBinary()) {
598 const char* data = tok[0]->begin(), *end = tok[0]->end();
600 char type;
601 uint32_t count;
602 ReadBinaryDataArrayHead(data, end, type, count, el);
604 if(count % 3 != 0) {
605 ParseError("number of floats is not a multiple of three (3) (binary)",&el);
606 }
608 if(!count) {
609 return;
610 }
612 if (type != 'd' && type != 'f') {
613 ParseError("expected float or double array (binary)",&el);
614 }
616 std::vector<char> buff;
617 ReadBinaryDataArray(type, count, data, end, buff, el);
619 ai_assert(data == end);
620 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
622 const uint32_t count3 = count / 3;
623 out.reserve(count3);
625 if (type == 'd') {
626 const double* d = reinterpret_cast<const double*>(&buff[0]);
627 for (unsigned int i = 0; i < count3; ++i, d += 3) {
628 out.push_back(aiVector3D(static_cast<float>(d[0]),
629 static_cast<float>(d[1]),
630 static_cast<float>(d[2])));
631 }
632 }
633 else if (type == 'f') {
634 const float* f = reinterpret_cast<const float*>(&buff[0]);
635 for (unsigned int i = 0; i < count3; ++i, f += 3) {
636 out.push_back(aiVector3D(f[0],f[1],f[2]));
637 }
638 }
640 return;
641 }
643 const size_t dim = ParseTokenAsDim(*tok[0]);
645 // may throw bad_alloc if the input is rubbish, but this need
646 // not to be prevented - importing would fail but we wouldn't
647 // crash since assimp handles this case properly.
648 out.reserve(dim);
650 const Scope& scope = GetRequiredScope(el);
651 const Element& a = GetRequiredElement(scope,"a",&el);
653 if (a.Tokens().size() % 3 != 0) {
654 ParseError("number of floats is not a multiple of three (3)",&el);
655 }
656 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
657 aiVector3D v;
658 v.x = ParseTokenAsFloat(**it++);
659 v.y = ParseTokenAsFloat(**it++);
660 v.z = ParseTokenAsFloat(**it++);
662 out.push_back(v);
663 }
664 }
667 // ------------------------------------------------------------------------------------------------
668 // read an array of color4 tuples
669 void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
670 {
671 out.clear();
672 const TokenList& tok = el.Tokens();
673 if(tok.empty()) {
674 ParseError("unexpected empty element",&el);
675 }
677 if(tok[0]->IsBinary()) {
678 const char* data = tok[0]->begin(), *end = tok[0]->end();
680 char type;
681 uint32_t count;
682 ReadBinaryDataArrayHead(data, end, type, count, el);
684 if(count % 4 != 0) {
685 ParseError("number of floats is not a multiple of four (4) (binary)",&el);
686 }
688 if(!count) {
689 return;
690 }
692 if (type != 'd' && type != 'f') {
693 ParseError("expected float or double array (binary)",&el);
694 }
696 std::vector<char> buff;
697 ReadBinaryDataArray(type, count, data, end, buff, el);
699 ai_assert(data == end);
700 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
702 const uint32_t count4 = count / 4;
703 out.reserve(count4);
705 if (type == 'd') {
706 const double* d = reinterpret_cast<const double*>(&buff[0]);
707 for (unsigned int i = 0; i < count4; ++i, d += 4) {
708 out.push_back(aiColor4D(static_cast<float>(d[0]),
709 static_cast<float>(d[1]),
710 static_cast<float>(d[2]),
711 static_cast<float>(d[3])));
712 }
713 }
714 else if (type == 'f') {
715 const float* f = reinterpret_cast<const float*>(&buff[0]);
716 for (unsigned int i = 0; i < count4; ++i, f += 4) {
717 out.push_back(aiColor4D(f[0],f[1],f[2],f[3]));
718 }
719 }
720 return;
721 }
723 const size_t dim = ParseTokenAsDim(*tok[0]);
725 // see notes in ParseVectorDataArray() above
726 out.reserve(dim);
728 const Scope& scope = GetRequiredScope(el);
729 const Element& a = GetRequiredElement(scope,"a",&el);
731 if (a.Tokens().size() % 4 != 0) {
732 ParseError("number of floats is not a multiple of four (4)",&el);
733 }
734 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
735 aiColor4D v;
736 v.r = ParseTokenAsFloat(**it++);
737 v.g = ParseTokenAsFloat(**it++);
738 v.b = ParseTokenAsFloat(**it++);
739 v.a = ParseTokenAsFloat(**it++);
741 out.push_back(v);
742 }
743 }
746 // ------------------------------------------------------------------------------------------------
747 // read an array of float2 tuples
748 void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
749 {
750 out.clear();
751 const TokenList& tok = el.Tokens();
752 if(tok.empty()) {
753 ParseError("unexpected empty element",&el);
754 }
756 if(tok[0]->IsBinary()) {
757 const char* data = tok[0]->begin(), *end = tok[0]->end();
759 char type;
760 uint32_t count;
761 ReadBinaryDataArrayHead(data, end, type, count, el);
763 if(count % 2 != 0) {
764 ParseError("number of floats is not a multiple of two (2) (binary)",&el);
765 }
767 if(!count) {
768 return;
769 }
771 if (type != 'd' && type != 'f') {
772 ParseError("expected float or double array (binary)",&el);
773 }
775 std::vector<char> buff;
776 ReadBinaryDataArray(type, count, data, end, buff, el);
778 ai_assert(data == end);
779 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
781 const uint32_t count2 = count / 2;
782 out.reserve(count2);
784 if (type == 'd') {
785 const double* d = reinterpret_cast<const double*>(&buff[0]);
786 for (unsigned int i = 0; i < count2; ++i, d += 2) {
787 out.push_back(aiVector2D(static_cast<float>(d[0]),
788 static_cast<float>(d[1])));
789 }
790 }
791 else if (type == 'f') {
792 const float* f = reinterpret_cast<const float*>(&buff[0]);
793 for (unsigned int i = 0; i < count2; ++i, f += 2) {
794 out.push_back(aiVector2D(f[0],f[1]));
795 }
796 }
798 return;
799 }
801 const size_t dim = ParseTokenAsDim(*tok[0]);
803 // see notes in ParseVectorDataArray() above
804 out.reserve(dim);
806 const Scope& scope = GetRequiredScope(el);
807 const Element& a = GetRequiredElement(scope,"a",&el);
809 if (a.Tokens().size() % 2 != 0) {
810 ParseError("number of floats is not a multiple of two (2)",&el);
811 }
812 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
813 aiVector2D v;
814 v.x = ParseTokenAsFloat(**it++);
815 v.y = ParseTokenAsFloat(**it++);
817 out.push_back(v);
818 }
819 }
822 // ------------------------------------------------------------------------------------------------
823 // read an array of ints
824 void ParseVectorDataArray(std::vector<int>& out, const Element& el)
825 {
826 out.clear();
827 const TokenList& tok = el.Tokens();
828 if(tok.empty()) {
829 ParseError("unexpected empty element",&el);
830 }
832 if(tok[0]->IsBinary()) {
833 const char* data = tok[0]->begin(), *end = tok[0]->end();
835 char type;
836 uint32_t count;
837 ReadBinaryDataArrayHead(data, end, type, count, el);
839 if(!count) {
840 return;
841 }
843 if (type != 'i') {
844 ParseError("expected int array (binary)",&el);
845 }
847 std::vector<char> buff;
848 ReadBinaryDataArray(type, count, data, end, buff, el);
850 ai_assert(data == end);
851 ai_assert(buff.size() == count * 4);
853 out.reserve(count);
855 const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
856 for (unsigned int i = 0; i < count; ++i, ++ip) {
857 BE_NCONST int32_t val = *ip;
858 AI_SWAP4(val);
859 out.push_back(val);
860 }
862 return;
863 }
865 const size_t dim = ParseTokenAsDim(*tok[0]);
867 // see notes in ParseVectorDataArray()
868 out.reserve(dim);
870 const Scope& scope = GetRequiredScope(el);
871 const Element& a = GetRequiredElement(scope,"a",&el);
873 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
874 const int ival = ParseTokenAsInt(**it++);
875 out.push_back(ival);
876 }
877 }
880 // ------------------------------------------------------------------------------------------------
881 // read an array of floats
882 void ParseVectorDataArray(std::vector<float>& out, const Element& el)
883 {
884 out.clear();
885 const TokenList& tok = el.Tokens();
886 if(tok.empty()) {
887 ParseError("unexpected empty element",&el);
888 }
890 if(tok[0]->IsBinary()) {
891 const char* data = tok[0]->begin(), *end = tok[0]->end();
893 char type;
894 uint32_t count;
895 ReadBinaryDataArrayHead(data, end, type, count, el);
897 if(!count) {
898 return;
899 }
901 if (type != 'd' && type != 'f') {
902 ParseError("expected float or double array (binary)",&el);
903 }
905 std::vector<char> buff;
906 ReadBinaryDataArray(type, count, data, end, buff, el);
908 ai_assert(data == end);
909 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
911 if (type == 'd') {
912 const double* d = reinterpret_cast<const double*>(&buff[0]);
913 for (unsigned int i = 0; i < count; ++i, ++d) {
914 out.push_back(static_cast<float>(*d));
915 }
916 }
917 else if (type == 'f') {
918 const float* f = reinterpret_cast<const float*>(&buff[0]);
919 for (unsigned int i = 0; i < count; ++i, ++f) {
920 out.push_back(*f);
921 }
922 }
924 return;
925 }
927 const size_t dim = ParseTokenAsDim(*tok[0]);
929 // see notes in ParseVectorDataArray()
930 out.reserve(dim);
932 const Scope& scope = GetRequiredScope(el);
933 const Element& a = GetRequiredElement(scope,"a",&el);
935 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
936 const float ival = ParseTokenAsFloat(**it++);
937 out.push_back(ival);
938 }
939 }
942 // ------------------------------------------------------------------------------------------------
943 // read an array of uints
944 void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
945 {
946 out.clear();
947 const TokenList& tok = el.Tokens();
948 if(tok.empty()) {
949 ParseError("unexpected empty element",&el);
950 }
952 if(tok[0]->IsBinary()) {
953 const char* data = tok[0]->begin(), *end = tok[0]->end();
955 char type;
956 uint32_t count;
957 ReadBinaryDataArrayHead(data, end, type, count, el);
959 if(!count) {
960 return;
961 }
963 if (type != 'i') {
964 ParseError("expected (u)int array (binary)",&el);
965 }
967 std::vector<char> buff;
968 ReadBinaryDataArray(type, count, data, end, buff, el);
970 ai_assert(data == end);
971 ai_assert(buff.size() == count * 4);
973 out.reserve(count);
975 const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
976 for (unsigned int i = 0; i < count; ++i, ++ip) {
977 BE_NCONST int32_t val = *ip;
978 if(val < 0) {
979 ParseError("encountered negative integer index (binary)");
980 }
982 AI_SWAP4(val);
983 out.push_back(val);
984 }
986 return;
987 }
989 const size_t dim = ParseTokenAsDim(*tok[0]);
991 // see notes in ParseVectorDataArray()
992 out.reserve(dim);
994 const Scope& scope = GetRequiredScope(el);
995 const Element& a = GetRequiredElement(scope,"a",&el);
997 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
998 const int ival = ParseTokenAsInt(**it++);
999 if(ival < 0) {
1000 ParseError("encountered negative integer index");
1001 }
1002 out.push_back(static_cast<unsigned int>(ival));
1003 }
1004 }
1007 // ------------------------------------------------------------------------------------------------
1008 // read an array of uint64_ts
1009 void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
1010 {
1011 out.clear();
1012 const TokenList& tok = el.Tokens();
1013 if(tok.empty()) {
1014 ParseError("unexpected empty element",&el);
1015 }
1017 if(tok[0]->IsBinary()) {
1018 const char* data = tok[0]->begin(), *end = tok[0]->end();
1020 char type;
1021 uint32_t count;
1022 ReadBinaryDataArrayHead(data, end, type, count, el);
1024 if(!count) {
1025 return;
1026 }
1028 if (type != 'l') {
1029 ParseError("expected long array (binary)",&el);
1030 }
1032 std::vector<char> buff;
1033 ReadBinaryDataArray(type, count, data, end, buff, el);
1035 ai_assert(data == end);
1036 ai_assert(buff.size() == count * 8);
1038 out.reserve(count);
1040 const uint64_t* ip = reinterpret_cast<const uint64_t*>(&buff[0]);
1041 for (unsigned int i = 0; i < count; ++i, ++ip) {
1042 BE_NCONST uint64_t val = *ip;
1043 AI_SWAP8(val);
1044 out.push_back(val);
1045 }
1047 return;
1048 }
1050 const size_t dim = ParseTokenAsDim(*tok[0]);
1052 // see notes in ParseVectorDataArray()
1053 out.reserve(dim);
1055 const Scope& scope = GetRequiredScope(el);
1056 const Element& a = GetRequiredElement(scope,"a",&el);
1058 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
1059 const uint64_t ival = ParseTokenAsID(**it++);
1061 out.push_back(ival);
1062 }
1063 }
1066 // ------------------------------------------------------------------------------------------------
1067 aiMatrix4x4 ReadMatrix(const Element& element)
1068 {
1069 std::vector<float> values;
1070 ParseVectorDataArray(values,element);
1072 if(values.size() != 16) {
1073 ParseError("expected 16 matrix elements");
1074 }
1076 aiMatrix4x4 result;
1079 result.a1 = values[0];
1080 result.a2 = values[1];
1081 result.a3 = values[2];
1082 result.a4 = values[3];
1084 result.b1 = values[4];
1085 result.b2 = values[5];
1086 result.b3 = values[6];
1087 result.b4 = values[7];
1089 result.c1 = values[8];
1090 result.c2 = values[9];
1091 result.c3 = values[10];
1092 result.c4 = values[11];
1094 result.d1 = values[12];
1095 result.d2 = values[13];
1096 result.d3 = values[14];
1097 result.d4 = values[15];
1099 result.Transpose();
1100 return result;
1101 }
1104 // ------------------------------------------------------------------------------------------------
1105 // wrapper around ParseTokenAsString() with ParseError handling
1106 std::string ParseTokenAsString(const Token& t)
1107 {
1108 const char* err;
1109 const std::string& i = ParseTokenAsString(t,err);
1110 if(err) {
1111 ParseError(err,t);
1112 }
1113 return i;
1114 }
1117 // ------------------------------------------------------------------------------------------------
1118 // extract a required element from a scope, abort if the element cannot be found
1119 const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/)
1120 {
1121 const Element* el = sc[index];
1122 if(!el) {
1123 ParseError("did not find required element \"" + index + "\"",element);
1124 }
1125 return *el;
1126 }
1129 // ------------------------------------------------------------------------------------------------
1130 // extract required compound scope
1131 const Scope& GetRequiredScope(const Element& el)
1132 {
1133 const Scope* const s = el.Compound();
1134 if(!s) {
1135 ParseError("expected compound scope",&el);
1136 }
1138 return *s;
1139 }
1142 // ------------------------------------------------------------------------------------------------
1143 // get token at a particular index
1144 const Token& GetRequiredToken(const Element& el, unsigned int index)
1145 {
1146 const TokenList& t = el.Tokens();
1147 if(index >= t.size()) {
1148 ParseError(Formatter::format( "missing token at index " ) << index,&el);
1149 }
1151 return *t[index];
1152 }
1155 // ------------------------------------------------------------------------------------------------
1156 // wrapper around ParseTokenAsID() with ParseError handling
1157 uint64_t ParseTokenAsID(const Token& t)
1158 {
1159 const char* err;
1160 const uint64_t i = ParseTokenAsID(t,err);
1161 if(err) {
1162 ParseError(err,t);
1163 }
1164 return i;
1165 }
1168 // ------------------------------------------------------------------------------------------------
1169 // wrapper around ParseTokenAsDim() with ParseError handling
1170 size_t ParseTokenAsDim(const Token& t)
1171 {
1172 const char* err;
1173 const size_t i = ParseTokenAsDim(t,err);
1174 if(err) {
1175 ParseError(err,t);
1176 }
1177 return i;
1178 }
1181 // ------------------------------------------------------------------------------------------------
1182 // wrapper around ParseTokenAsFloat() with ParseError handling
1183 float ParseTokenAsFloat(const Token& t)
1184 {
1185 const char* err;
1186 const float i = ParseTokenAsFloat(t,err);
1187 if(err) {
1188 ParseError(err,t);
1189 }
1190 return i;
1191 }
1194 // ------------------------------------------------------------------------------------------------
1195 // wrapper around ParseTokenAsInt() with ParseError handling
1196 int ParseTokenAsInt(const Token& t)
1197 {
1198 const char* err;
1199 const int i = ParseTokenAsInt(t,err);
1200 if(err) {
1201 ParseError(err,t);
1202 }
1203 return i;
1204 }
1208 } // !FBX
1209 } // !Assimp
1211 #endif