1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14 copyright notice, this list of conditions and the
15 following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18 copyright notice, this list of conditions and the
19 following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23 contributors may be used to endorse or promote products
24 derived from this software without specific prior
25 written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42/** @file FBXParser.cpp
43 * @brief Implementation of the FBX parser and the rudimentary DOM that we use
44 */
45
46#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
47
48
49#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
50# include <zlib.h>
51#else
52# include "../contrib/zlib/zlib.h"
53#endif
54
55#include "FBXTokenizer.h"
56#include "FBXParser.h"
57#include "FBXUtil.h"
58
59#include "ParsingUtils.h"
60#include "fast_atof.h"
61#include "ByteSwapper.h"
62
63#include <iostream>
64
65using namespace Assimp;
66using namespace Assimp::FBX;
67
68namespace {
69
70
71 // ------------------------------------------------------------------------------------------------
72 // signal parse error, this is always unrecoverable. Throws DeadlyImportError.
73 AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX;
74 AI_WONT_RETURN void ParseError(const std::string& message, const Token& token)
75 {
76 throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token));
77 }
78
79 // ------------------------------------------------------------------------------------------------
80 AI_WONT_RETURN void ParseError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX;
81 AI_WONT_RETURN void ParseError(const std::string& message, const Element* element)
82 {
83 if(element) {
84 ParseError(message,element->KeyToken());
85 }
86 throw DeadlyImportError("FBX-Parser " + message);
87 }
88
89
90 // ------------------------------------------------------------------------------------------------
91 void ParseError(const std::string& message, TokenPtr token)
92 {
93 if(token) {
94 ParseError(message, *token);
95 }
96 ParseError(message);
97 }
98
99 // Initially, we did reinterpret_cast, breaking strict aliasing rules.
100 // This actually caused trouble on Android, so let's be safe this time.
101 // https://github.com/assimp/assimp/issues/24
102 template <typename T>
103 T SafeParse(const char* data, const char* end) {
104 // Actual size validation happens during Tokenization so
105 // this is valid as an assertion.
106 (void)(end);
107 ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
108 T result = static_cast<T>(0);
109 ::memcpy(&result, data, sizeof(T));
110 return result;
111 }
112}
113
114namespace Assimp {
115namespace FBX {
116
117// ------------------------------------------------------------------------------------------------
118Element::Element(const Token& key_token, Parser& parser)
119: key_token(key_token)
120{
121 TokenPtr n = NULL;
122 do {
123 n = parser.AdvanceToNextToken();
124 if(!n) {
125 ParseError("unexpected end of file, expected closing bracket",parser.LastToken());
126 }
127
128 if (n->Type() == TokenType_DATA) {
129 tokens.push_back(n);
130 TokenPtr prev = n;
131 n = parser.AdvanceToNextToken();
132 if(!n) {
133 ParseError("unexpected end of file, expected bracket, comma or key",parser.LastToken());
134 }
135
136 const TokenType ty = n->Type();
137
138 // some exporters are missing a comma on the next line
139 if (ty == TokenType_DATA && prev->Type() == TokenType_DATA && (n->Line() == prev->Line() + 1)) {
140 tokens.push_back(n);
141 continue;
142 }
143
144 if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) {
145 ParseError("unexpected token; expected bracket, comma or key",n);
146 }
147 }
148
149 if (n->Type() == TokenType_OPEN_BRACKET) {
150 compound.reset(new Scope(parser));
151
152 // current token should be a TOK_CLOSE_BRACKET
153 n = parser.CurrentToken();
154 ai_assert(n);
155
156 if (n->Type() != TokenType_CLOSE_BRACKET) {
157 ParseError("expected closing bracket",n);
158 }
159
160 parser.AdvanceToNextToken();
161 return;
162 }
163 }
164 while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
165}
166
167// ------------------------------------------------------------------------------------------------
168Element::~Element()
169{
170 // no need to delete tokens, they are owned by the parser
171}
172
173// ------------------------------------------------------------------------------------------------
174Scope::Scope(Parser& parser,bool topLevel)
175{
176 if(!topLevel) {
177 TokenPtr t = parser.CurrentToken();
178 if (t->Type() != TokenType_OPEN_BRACKET) {
179 ParseError("expected open bracket",t);
180 }
181 }
182
183 TokenPtr n = parser.AdvanceToNextToken();
184 if(n == NULL) {
185 ParseError("unexpected end of file");
186 }
187
188 // note: empty scopes are allowed
189 while(n->Type() != TokenType_CLOSE_BRACKET) {
190 if (n->Type() != TokenType_KEY) {
191 ParseError("unexpected token, expected TOK_KEY",n);
192 }
193
194 const std::string& str = n->StringContents();
195 elements.insert(ElementMap::value_type(str,new_Element(*n,parser)));
196
197 // Element() should stop at the next Key token (or right after a Close token)
198 n = parser.CurrentToken();
199 if(n == NULL) {
200 if (topLevel) {
201 return;
202 }
203 ParseError("unexpected end of file",parser.LastToken());
204 }
205 }
206}
207
208// ------------------------------------------------------------------------------------------------
209Scope::~Scope()
210{
211 for(ElementMap::value_type& v : elements) {
212 delete v.second;
213 }
214}
215
216
217// ------------------------------------------------------------------------------------------------
218Parser::Parser (const TokenList& tokens, bool is_binary)
219: tokens(tokens)
220, last()
221, current()
222, cursor(tokens.begin())
223, is_binary(is_binary)
224{
225 root.reset(new Scope(*this,true));
226}
227
228// ------------------------------------------------------------------------------------------------
229Parser::~Parser()
230{
231 // empty
232}
233
234// ------------------------------------------------------------------------------------------------
235TokenPtr Parser::AdvanceToNextToken()
236{
237 last = current;
238 if (cursor == tokens.end()) {
239 current = NULL;
240 } else {
241 current = *cursor++;
242 }
243 return current;
244}
245
246// ------------------------------------------------------------------------------------------------
247TokenPtr Parser::CurrentToken() const
248{
249 return current;
250}
251
252// ------------------------------------------------------------------------------------------------
253TokenPtr Parser::LastToken() const
254{
255 return last;
256}
257
258// ------------------------------------------------------------------------------------------------
259uint64_t ParseTokenAsID(const Token& t, const char*& err_out)
260{
261 err_out = NULL;
262
263 if (t.Type() != TokenType_DATA) {
264 err_out = "expected TOK_DATA token";
265 return 0L;
266 }
267
268 if(t.IsBinary())
269 {
270 const char* data = t.begin();
271 if (data[0] != 'L') {
272 err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
273 return 0L;
274 }
275
276 BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end());
277 AI_SWAP8(id);
278 return id;
279 }
280
281 // XXX: should use size_t here
282 unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
283 ai_assert(length > 0);
284
285 const char* out = nullptr;
286 const uint64_t id = strtoul10_64(t.begin(),&out,&length);
287 if (out > t.end()) {
288 err_out = "failed to parse ID (text)";
289 return 0L;
290 }
291
292 return id;
293}
294
295// ------------------------------------------------------------------------------------------------
296size_t ParseTokenAsDim(const Token& t, const char*& err_out)
297{
298 // same as ID parsing, except there is a trailing asterisk
299 err_out = NULL;
300
301 if (t.Type() != TokenType_DATA) {
302 err_out = "expected TOK_DATA token";
303 return 0;
304 }
305
306 if(t.IsBinary())
307 {
308 const char* data = t.begin();
309 if (data[0] != 'L') {
310 err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)";
311 return 0;
312 }
313
314 BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end());
315 AI_SWAP8(id);
316 return static_cast<size_t>(id);
317 }
318
319 if(*t.begin() != '*') {
320 err_out = "expected asterisk before array dimension";
321 return 0;
322 }
323
324 // XXX: should use size_t here
325 unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
326 if(length == 0) {
327 err_out = "expected valid integer number after asterisk";
328 return 0;
329 }
330
331 const char* out = nullptr;
332 const size_t id = static_cast<size_t>(strtoul10_64(t.begin() + 1,&out,&length));
333 if (out > t.end()) {
334 err_out = "failed to parse ID";
335 return 0;
336 }
337
338 return id;
339}
340
341
342// ------------------------------------------------------------------------------------------------
343float ParseTokenAsFloat(const Token& t, const char*& err_out)
344{
345 err_out = NULL;
346
347 if (t.Type() != TokenType_DATA) {
348 err_out = "expected TOK_DATA token";
349 return 0.0f;
350 }
351
352 if(t.IsBinary())
353 {
354 const char* data = t.begin();
355 if (data[0] != 'F' && data[0] != 'D') {
356 err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)";
357 return 0.0f;
358 }
359
360 if (data[0] == 'F') {
361 return SafeParse<float>(data+1, t.end());
362 }
363 else {
364 return static_cast<float>( SafeParse<double>(data+1, t.end()) );
365 }
366 }
367
368 // need to copy the input string to a temporary buffer
369 // first - next in the fbx token stream comes ',',
370 // which fast_atof could interpret as decimal point.
371#define MAX_FLOAT_LENGTH 31
372 char temp[MAX_FLOAT_LENGTH + 1];
373 const size_t length = static_cast<size_t>(t.end()-t.begin());
374 std::copy(t.begin(),t.end(),temp);
375 temp[std::min(static_cast<size_t>(MAX_FLOAT_LENGTH),length)] = '\0';
376
377 return fast_atof(temp);
378}
379
380
381// ------------------------------------------------------------------------------------------------
382int ParseTokenAsInt(const Token& t, const char*& err_out)
383{
384 err_out = NULL;
385
386 if (t.Type() != TokenType_DATA) {
387 err_out = "expected TOK_DATA token";
388 return 0;
389 }
390
391 if(t.IsBinary())
392 {
393 const char* data = t.begin();
394 if (data[0] != 'I') {
395 err_out = "failed to parse I(nt), unexpected data type (binary)";
396 return 0;
397 }
398
399 BE_NCONST int32_t ival = SafeParse<int32_t>(data+1, t.end());
400 AI_SWAP4(ival);
401 return static_cast<int>(ival);
402 }
403
404 ai_assert(static_cast<size_t>(t.end() - t.begin()) > 0);
405
406 const char* out;
407 const int intval = strtol10(t.begin(),&out);
408 if (out != t.end()) {
409 err_out = "failed to parse ID";
410 return 0;
411 }
412
413 return intval;
414}
415
416
417// ------------------------------------------------------------------------------------------------
418int64_t ParseTokenAsInt64(const Token& t, const char*& err_out)
419{
420 err_out = NULL;
421
422 if (t.Type() != TokenType_DATA) {
423 err_out = "expected TOK_DATA token";
424 return 0L;
425 }
426
427 if (t.IsBinary())
428 {
429 const char* data = t.begin();
430 if (data[0] != 'L') {
431 err_out = "failed to parse Int64, unexpected data type";
432 return 0L;
433 }
434
435 BE_NCONST int64_t id = SafeParse<int64_t>(data + 1, t.end());
436 AI_SWAP8(id);
437 return id;
438 }
439
440 // XXX: should use size_t here
441 unsigned int length = static_cast<unsigned int>(t.end() - t.begin());
442 ai_assert(length > 0);
443
444 const char* out = nullptr;
445 const int64_t id = strtol10_64(t.begin(), &out, &length);
446 if (out > t.end()) {
447 err_out = "failed to parse Int64 (text)";
448 return 0L;
449 }
450
451 return id;
452}
453
454// ------------------------------------------------------------------------------------------------
455std::string ParseTokenAsString(const Token& t, const char*& err_out)
456{
457 err_out = NULL;
458
459 if (t.Type() != TokenType_DATA) {
460 err_out = "expected TOK_DATA token";
461 return "";
462 }
463
464 if(t.IsBinary())
465 {
466 const char* data = t.begin();
467 if (data[0] != 'S') {
468 err_out = "failed to parse S(tring), unexpected data type (binary)";
469 return "";
470 }
471
472 // read string length
473 BE_NCONST int32_t len = SafeParse<int32_t>(data+1, t.end());
474 AI_SWAP4(len);
475
476 ai_assert(t.end() - data == 5 + len);
477 return std::string(data + 5, len);
478 }
479
480 const size_t length = static_cast<size_t>(t.end() - t.begin());
481 if(length < 2) {
482 err_out = "token is too short to hold a string";
483 return "";
484 }
485
486 const char* s = t.begin(), *e = t.end() - 1;
487 if (*s != '\"' || *e != '\"') {
488 err_out = "expected double quoted string";
489 return "";
490 }
491
492 return std::string(s+1,length-2);
493}
494
495
496namespace {
497
498// ------------------------------------------------------------------------------------------------
499// read the type code and element count of a binary data array and stop there
500void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uint32_t& count,
501 const Element& el)
502{
503 if (static_cast<size_t>(end-data) < 5) {
504 ParseError("binary data array is too short, need five (5) bytes for type signature and element count",&el);
505 }
506
507 // data type
508 type = *data;
509
510 // read number of elements
511 BE_NCONST uint32_t len = SafeParse<uint32_t>(data+1, end);
512 AI_SWAP4(len);
513
514 count = len;
515 data += 5;
516}
517
518
519// ------------------------------------------------------------------------------------------------
520// read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
521void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end,
522 std::vector<char>& buff,
523 const Element& /*el*/)
524{
525 BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end);
526 AI_SWAP4(encmode);
527 data += 4;
528
529 // next comes the compressed length
530 BE_NCONST uint32_t comp_len = SafeParse<uint32_t>(data, end);
531 AI_SWAP4(comp_len);
532 data += 4;
533
534 ai_assert(data + comp_len == end);
535
536 // determine the length of the uncompressed data by looking at the type signature
537 uint32_t stride = 0;
538 switch(type)
539 {
540 case 'f':
541 case 'i':
542 stride = 4;
543 break;
544
545 case 'd':
546 case 'l':
547 stride = 8;
548 break;
549
550 default:
551 ai_assert(false);
552 };
553
554 const uint32_t full_length = stride * count;
555 buff.resize(full_length);
556
557 if(encmode == 0) {
558 ai_assert(full_length == comp_len);
559
560 // plain data, no compression
561 std::copy(data, end, buff.begin());
562 }
563 else if(encmode == 1) {
564 // zlib/deflate, next comes ZIP head (0x78 0x01)
565 // see http://www.ietf.org/rfc/rfc1950.txt
566
567 z_stream zstream;
568 zstream.opaque = Z_NULL;
569 zstream.zalloc = Z_NULL;
570 zstream.zfree = Z_NULL;
571 zstream.data_type = Z_BINARY;
572
573 // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
574 if(Z_OK != inflateInit(&zstream)) {
575 ParseError("failure initializing zlib");
576 }
577
578 zstream.next_in = reinterpret_cast<Bytef*>( const_cast<char*>(data) );
579 zstream.avail_in = comp_len;
580
581 zstream.avail_out = static_cast<uInt>(buff.size());
582 zstream.next_out = reinterpret_cast<Bytef*>(&*buff.begin());
583 const int ret = inflate(&zstream, Z_FINISH);
584
585 if (ret != Z_STREAM_END && ret != Z_OK) {
586 ParseError("failure decompressing compressed data section");
587 }
588
589 // terminate zlib
590 inflateEnd(&zstream);
591 }
592#ifdef ASSIMP_BUILD_DEBUG
593 else {
594 // runtime check for this happens at tokenization stage
595 ai_assert(false);
596 }
597#endif
598
599 data += comp_len;
600 ai_assert(data == end);
601}
602
603} // !anon
604
605
606// ------------------------------------------------------------------------------------------------
607// read an array of float3 tuples
608void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
609{
610 out.resize( 0 );
611
612 const TokenList& tok = el.Tokens();
613 if(tok.empty()) {
614 ParseError("unexpected empty element",&el);
615 }
616
617 if(tok[0]->IsBinary()) {
618 const char* data = tok[0]->begin(), *end = tok[0]->end();
619
620 char type;
621 uint32_t count;
622 ReadBinaryDataArrayHead(data, end, type, count, el);
623
624 if(count % 3 != 0) {
625 ParseError("number of floats is not a multiple of three (3) (binary)",&el);
626 }
627
628 if(!count) {
629 return;
630 }
631
632 if (type != 'd' && type != 'f') {
633 ParseError("expected float or double array (binary)",&el);
634 }
635
636 std::vector<char> buff;
637 ReadBinaryDataArray(type, count, data, end, buff, el);
638
639 ai_assert(data == end);
640 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
641
642 const uint32_t count3 = count / 3;
643 out.reserve(count3);
644
645 if (type == 'd') {
646 const double* d = reinterpret_cast<const double*>(&buff[0]);
647 for (unsigned int i = 0; i < count3; ++i, d += 3) {
648 out.push_back(aiVector3D(static_cast<float>(d[0]),
649 static_cast<float>(d[1]),
650 static_cast<float>(d[2])));
651 }
652 // for debugging
653 /*for ( size_t i = 0; i < out.size(); i++ ) {
654 aiVector3D vec3( out[ i ] );
655 std::stringstream stream;
656 stream << " vec3.x = " << vec3.x << " vec3.y = " << vec3.y << " vec3.z = " << vec3.z << std::endl;
657 DefaultLogger::get()->info( stream.str() );
658 }*/
659 }
660 else if (type == 'f') {
661 const float* f = reinterpret_cast<const float*>(&buff[0]);
662 for (unsigned int i = 0; i < count3; ++i, f += 3) {
663 out.push_back(aiVector3D(f[0],f[1],f[2]));
664 }
665 }
666
667 return;
668 }
669
670 const size_t dim = ParseTokenAsDim(*tok[0]);
671
672 // may throw bad_alloc if the input is rubbish, but this need
673 // not to be prevented - importing would fail but we wouldn't
674 // crash since assimp handles this case properly.
675 out.reserve(dim);
676
677 const Scope& scope = GetRequiredScope(el);
678 const Element& a = GetRequiredElement(scope,"a",&el);
679
680 if (a.Tokens().size() % 3 != 0) {
681 ParseError("number of floats is not a multiple of three (3)",&el);
682 }
683 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
684 aiVector3D v;
685 v.x = ParseTokenAsFloat(**it++);
686 v.y = ParseTokenAsFloat(**it++);
687 v.z = ParseTokenAsFloat(**it++);
688
689 out.push_back(v);
690 }
691}
692
693
694// ------------------------------------------------------------------------------------------------
695// read an array of color4 tuples
696void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
697{
698 out.resize( 0 );
699 const TokenList& tok = el.Tokens();
700 if(tok.empty()) {
701 ParseError("unexpected empty element",&el);
702 }
703
704 if(tok[0]->IsBinary()) {
705 const char* data = tok[0]->begin(), *end = tok[0]->end();
706
707 char type;
708 uint32_t count;
709 ReadBinaryDataArrayHead(data, end, type, count, el);
710
711 if(count % 4 != 0) {
712 ParseError("number of floats is not a multiple of four (4) (binary)",&el);
713 }
714
715 if(!count) {
716 return;
717 }
718
719 if (type != 'd' && type != 'f') {
720 ParseError("expected float or double array (binary)",&el);
721 }
722
723 std::vector<char> buff;
724 ReadBinaryDataArray(type, count, data, end, buff, el);
725
726 ai_assert(data == end);
727 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
728
729 const uint32_t count4 = count / 4;
730 out.reserve(count4);
731
732 if (type == 'd') {
733 const double* d = reinterpret_cast<const double*>(&buff[0]);
734 for (unsigned int i = 0; i < count4; ++i, d += 4) {
735 out.push_back(aiColor4D(static_cast<float>(d[0]),
736 static_cast<float>(d[1]),
737 static_cast<float>(d[2]),
738 static_cast<float>(d[3])));
739 }
740 }
741 else if (type == 'f') {
742 const float* f = reinterpret_cast<const float*>(&buff[0]);
743 for (unsigned int i = 0; i < count4; ++i, f += 4) {
744 out.push_back(aiColor4D(f[0],f[1],f[2],f[3]));
745 }
746 }
747 return;
748 }
749
750 const size_t dim = ParseTokenAsDim(*tok[0]);
751
752 // see notes in ParseVectorDataArray() above
753 out.reserve(dim);
754
755 const Scope& scope = GetRequiredScope(el);
756 const Element& a = GetRequiredElement(scope,"a",&el);
757
758 if (a.Tokens().size() % 4 != 0) {
759 ParseError("number of floats is not a multiple of four (4)",&el);
760 }
761 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
762 aiColor4D v;
763 v.r = ParseTokenAsFloat(**it++);
764 v.g = ParseTokenAsFloat(**it++);
765 v.b = ParseTokenAsFloat(**it++);
766 v.a = ParseTokenAsFloat(**it++);
767
768 out.push_back(v);
769 }
770}
771
772
773// ------------------------------------------------------------------------------------------------
774// read an array of float2 tuples
775void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
776{
777 out.resize( 0 );
778 const TokenList& tok = el.Tokens();
779 if(tok.empty()) {
780 ParseError("unexpected empty element",&el);
781 }
782
783 if(tok[0]->IsBinary()) {
784 const char* data = tok[0]->begin(), *end = tok[0]->end();
785
786 char type;
787 uint32_t count;
788 ReadBinaryDataArrayHead(data, end, type, count, el);
789
790 if(count % 2 != 0) {
791 ParseError("number of floats is not a multiple of two (2) (binary)",&el);
792 }
793
794 if(!count) {
795 return;
796 }
797
798 if (type != 'd' && type != 'f') {
799 ParseError("expected float or double array (binary)",&el);
800 }
801
802 std::vector<char> buff;
803 ReadBinaryDataArray(type, count, data, end, buff, el);
804
805 ai_assert(data == end);
806 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
807
808 const uint32_t count2 = count / 2;
809 out.reserve(count2);
810
811 if (type == 'd') {
812 const double* d = reinterpret_cast<const double*>(&buff[0]);
813 for (unsigned int i = 0; i < count2; ++i, d += 2) {
814 out.push_back(aiVector2D(static_cast<float>(d[0]),
815 static_cast<float>(d[1])));
816 }
817 }
818 else if (type == 'f') {
819 const float* f = reinterpret_cast<const float*>(&buff[0]);
820 for (unsigned int i = 0; i < count2; ++i, f += 2) {
821 out.push_back(aiVector2D(f[0],f[1]));
822 }
823 }
824
825 return;
826 }
827
828 const size_t dim = ParseTokenAsDim(*tok[0]);
829
830 // see notes in ParseVectorDataArray() above
831 out.reserve(dim);
832
833 const Scope& scope = GetRequiredScope(el);
834 const Element& a = GetRequiredElement(scope,"a",&el);
835
836 if (a.Tokens().size() % 2 != 0) {
837 ParseError("number of floats is not a multiple of two (2)",&el);
838 }
839 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
840 aiVector2D v;
841 v.x = ParseTokenAsFloat(**it++);
842 v.y = ParseTokenAsFloat(**it++);
843
844 out.push_back(v);
845 }
846}
847
848
849// ------------------------------------------------------------------------------------------------
850// read an array of ints
851void ParseVectorDataArray(std::vector<int>& out, const Element& el)
852{
853 out.resize( 0 );
854 const TokenList& tok = el.Tokens();
855 if(tok.empty()) {
856 ParseError("unexpected empty element",&el);
857 }
858
859 if(tok[0]->IsBinary()) {
860 const char* data = tok[0]->begin(), *end = tok[0]->end();
861
862 char type;
863 uint32_t count;
864 ReadBinaryDataArrayHead(data, end, type, count, el);
865
866 if(!count) {
867 return;
868 }
869
870 if (type != 'i') {
871 ParseError("expected int array (binary)",&el);
872 }
873
874 std::vector<char> buff;
875 ReadBinaryDataArray(type, count, data, end, buff, el);
876
877 ai_assert(data == end);
878 ai_assert(buff.size() == count * 4);
879
880 out.reserve(count);
881
882 const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
883 for (unsigned int i = 0; i < count; ++i, ++ip) {
884 BE_NCONST int32_t val = *ip;
885 AI_SWAP4(val);
886 out.push_back(val);
887 }
888
889 return;
890 }
891
892 const size_t dim = ParseTokenAsDim(*tok[0]);
893
894 // see notes in ParseVectorDataArray()
895 out.reserve(dim);
896
897 const Scope& scope = GetRequiredScope(el);
898 const Element& a = GetRequiredElement(scope,"a",&el);
899
900 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
901 const int ival = ParseTokenAsInt(**it++);
902 out.push_back(ival);
903 }
904}
905
906
907// ------------------------------------------------------------------------------------------------
908// read an array of floats
909void ParseVectorDataArray(std::vector<float>& out, const Element& el)
910{
911 out.resize( 0 );
912 const TokenList& tok = el.Tokens();
913 if(tok.empty()) {
914 ParseError("unexpected empty element",&el);
915 }
916
917 if(tok[0]->IsBinary()) {
918 const char* data = tok[0]->begin(), *end = tok[0]->end();
919
920 char type;
921 uint32_t count;
922 ReadBinaryDataArrayHead(data, end, type, count, el);
923
924 if(!count) {
925 return;
926 }
927
928 if (type != 'd' && type != 'f') {
929 ParseError("expected float or double array (binary)",&el);
930 }
931
932 std::vector<char> buff;
933 ReadBinaryDataArray(type, count, data, end, buff, el);
934
935 ai_assert(data == end);
936 ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
937
938 if (type == 'd') {
939 const double* d = reinterpret_cast<const double*>(&buff[0]);
940 for (unsigned int i = 0; i < count; ++i, ++d) {
941 out.push_back(static_cast<float>(*d));
942 }
943 }
944 else if (type == 'f') {
945 const float* f = reinterpret_cast<const float*>(&buff[0]);
946 for (unsigned int i = 0; i < count; ++i, ++f) {
947 out.push_back(*f);
948 }
949 }
950
951 return;
952 }
953
954 const size_t dim = ParseTokenAsDim(*tok[0]);
955
956 // see notes in ParseVectorDataArray()
957 out.reserve(dim);
958
959 const Scope& scope = GetRequiredScope(el);
960 const Element& a = GetRequiredElement(scope,"a",&el);
961
962 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
963 const float ival = ParseTokenAsFloat(**it++);
964 out.push_back(ival);
965 }
966}
967
968
969// ------------------------------------------------------------------------------------------------
970// read an array of uints
971void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
972{
973 out.resize( 0 );
974 const TokenList& tok = el.Tokens();
975 if(tok.empty()) {
976 ParseError("unexpected empty element",&el);
977 }
978
979 if(tok[0]->IsBinary()) {
980 const char* data = tok[0]->begin(), *end = tok[0]->end();
981
982 char type;
983 uint32_t count;
984 ReadBinaryDataArrayHead(data, end, type, count, el);
985
986 if(!count) {
987 return;
988 }
989
990 if (type != 'i') {
991 ParseError("expected (u)int array (binary)",&el);
992 }
993
994 std::vector<char> buff;
995 ReadBinaryDataArray(type, count, data, end, buff, el);
996
997 ai_assert(data == end);
998 ai_assert(buff.size() == count * 4);
999
1000 out.reserve(count);
1001
1002 const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]);
1003 for (unsigned int i = 0; i < count; ++i, ++ip) {
1004 BE_NCONST int32_t val = *ip;
1005 if(val < 0) {
1006 ParseError("encountered negative integer index (binary)");
1007 }
1008
1009 AI_SWAP4(val);
1010 out.push_back(val);
1011 }
1012
1013 return;
1014 }
1015
1016 const size_t dim = ParseTokenAsDim(*tok[0]);
1017
1018 // see notes in ParseVectorDataArray()
1019 out.reserve(dim);
1020
1021 const Scope& scope = GetRequiredScope(el);
1022 const Element& a = GetRequiredElement(scope,"a",&el);
1023
1024 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
1025 const int ival = ParseTokenAsInt(**it++);
1026 if(ival < 0) {
1027 ParseError("encountered negative integer index");
1028 }
1029 out.push_back(static_cast<unsigned int>(ival));
1030 }
1031}
1032
1033
1034// ------------------------------------------------------------------------------------------------
1035// read an array of uint64_ts
1036void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
1037{
1038 out.resize( 0 );
1039 const TokenList& tok = el.Tokens();
1040 if(tok.empty()) {
1041 ParseError("unexpected empty element",&el);
1042 }
1043
1044 if(tok[0]->IsBinary()) {
1045 const char* data = tok[0]->begin(), *end = tok[0]->end();
1046
1047 char type;
1048 uint32_t count;
1049 ReadBinaryDataArrayHead(data, end, type, count, el);
1050
1051 if(!count) {
1052 return;
1053 }
1054
1055 if (type != 'l') {
1056 ParseError("expected long array (binary)",&el);
1057 }
1058
1059 std::vector<char> buff;
1060 ReadBinaryDataArray(type, count, data, end, buff, el);
1061
1062 ai_assert(data == end);
1063 ai_assert(buff.size() == count * 8);
1064
1065 out.reserve(count);
1066
1067 const uint64_t* ip = reinterpret_cast<const uint64_t*>(&buff[0]);
1068 for (unsigned int i = 0; i < count; ++i, ++ip) {
1069 BE_NCONST uint64_t val = *ip;
1070 AI_SWAP8(val);
1071 out.push_back(val);
1072 }
1073
1074 return;
1075 }
1076
1077 const size_t dim = ParseTokenAsDim(*tok[0]);
1078
1079 // see notes in ParseVectorDataArray()
1080 out.reserve(dim);
1081
1082 const Scope& scope = GetRequiredScope(el);
1083 const Element& a = GetRequiredElement(scope,"a",&el);
1084
1085 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) {
1086 const uint64_t ival = ParseTokenAsID(**it++);
1087
1088 out.push_back(ival);
1089 }
1090}
1091
1092// ------------------------------------------------------------------------------------------------
1093// read an array of int64_ts
1094void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el)
1095{
1096 out.resize( 0 );
1097 const TokenList& tok = el.Tokens();
1098 if (tok.empty()) {
1099 ParseError("unexpected empty element", &el);
1100 }
1101
1102 if (tok[0]->IsBinary()) {
1103 const char* data = tok[0]->begin(), *end = tok[0]->end();
1104
1105 char type;
1106 uint32_t count;
1107 ReadBinaryDataArrayHead(data, end, type, count, el);
1108
1109 if (!count) {
1110 return;
1111 }
1112
1113 if (type != 'l') {
1114 ParseError("expected long array (binary)", &el);
1115 }
1116
1117 std::vector<char> buff;
1118 ReadBinaryDataArray(type, count, data, end, buff, el);
1119
1120 ai_assert(data == end);
1121 ai_assert(buff.size() == count * 8);
1122
1123 out.reserve(count);
1124
1125 const int64_t* ip = reinterpret_cast<const int64_t*>(&buff[0]);
1126 for (unsigned int i = 0; i < count; ++i, ++ip) {
1127 BE_NCONST int64_t val = *ip;
1128 AI_SWAP8(val);
1129 out.push_back(val);
1130 }
1131
1132 return;
1133 }
1134
1135 const size_t dim = ParseTokenAsDim(*tok[0]);
1136
1137 // see notes in ParseVectorDataArray()
1138 out.reserve(dim);
1139
1140 const Scope& scope = GetRequiredScope(el);
1141 const Element& a = GetRequiredElement(scope, "a", &el);
1142
1143 for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end;) {
1144 const int64_t ival = ParseTokenAsInt64(**it++);
1145
1146 out.push_back(ival);
1147 }
1148}
1149
1150// ------------------------------------------------------------------------------------------------
1151aiMatrix4x4 ReadMatrix(const Element& element)
1152{
1153 std::vector<float> values;
1154 ParseVectorDataArray(values,element);
1155
1156 if(values.size() != 16) {
1157 ParseError("expected 16 matrix elements");
1158 }
1159
1160 aiMatrix4x4 result;
1161
1162
1163 result.a1 = values[0];
1164 result.a2 = values[1];
1165 result.a3 = values[2];
1166 result.a4 = values[3];
1167
1168 result.b1 = values[4];
1169 result.b2 = values[5];
1170 result.b3 = values[6];
1171 result.b4 = values[7];
1172
1173 result.c1 = values[8];
1174 result.c2 = values[9];
1175 result.c3 = values[10];
1176 result.c4 = values[11];
1177
1178 result.d1 = values[12];
1179 result.d2 = values[13];
1180 result.d3 = values[14];
1181 result.d4 = values[15];
1182
1183 result.Transpose();
1184 return result;
1185}
1186
1187
1188// ------------------------------------------------------------------------------------------------
1189// wrapper around ParseTokenAsString() with ParseError handling
1190std::string ParseTokenAsString(const Token& t)
1191{
1192 const char* err;
1193 const std::string& i = ParseTokenAsString(t,err);
1194 if(err) {
1195 ParseError(err,t);
1196 }
1197 return i;
1198}
1199
1200
1201// ------------------------------------------------------------------------------------------------
1202// extract a required element from a scope, abort if the element cannot be found
1203const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/)
1204{
1205 const Element* el = sc[index];
1206 if(!el) {
1207 ParseError("did not find required element \"" + index + "\"",element);
1208 }
1209 return *el;
1210}
1211
1212
1213// ------------------------------------------------------------------------------------------------
1214// extract required compound scope
1215const Scope& GetRequiredScope(const Element& el)
1216{
1217 const Scope* const s = el.Compound();
1218 if(!s) {
1219 ParseError("expected compound scope",&el);
1220 }
1221
1222 return *s;
1223}
1224
1225
1226// ------------------------------------------------------------------------------------------------
1227// get token at a particular index
1228const Token& GetRequiredToken(const Element& el, unsigned int index)
1229{
1230 const TokenList& t = el.Tokens();
1231 if(index >= t.size()) {
1232 ParseError(Formatter::format( "missing token at index " ) << index,&el);
1233 }
1234
1235 return *t[index];
1236}
1237
1238
1239// ------------------------------------------------------------------------------------------------
1240// wrapper around ParseTokenAsID() with ParseError handling
1241uint64_t ParseTokenAsID(const Token& t)
1242{
1243 const char* err;
1244 const uint64_t i = ParseTokenAsID(t,err);
1245 if(err) {
1246 ParseError(err,t);
1247 }
1248 return i;
1249}
1250
1251
1252// ------------------------------------------------------------------------------------------------
1253// wrapper around ParseTokenAsDim() with ParseError handling
1254size_t ParseTokenAsDim(const Token& t)
1255{
1256 const char* err;
1257 const size_t i = ParseTokenAsDim(t,err);
1258 if(err) {
1259 ParseError(err,t);
1260 }
1261 return i;
1262}
1263
1264
1265// ------------------------------------------------------------------------------------------------
1266// wrapper around ParseTokenAsFloat() with ParseError handling
1267float ParseTokenAsFloat(const Token& t)
1268{
1269 const char* err;
1270 const float i = ParseTokenAsFloat(t,err);
1271 if(err) {
1272 ParseError(err,t);
1273 }
1274 return i;
1275}
1276
1277
1278// ------------------------------------------------------------------------------------------------
1279// wrapper around ParseTokenAsInt() with ParseError handling
1280int ParseTokenAsInt(const Token& t)
1281{
1282 const char* err;
1283 const int i = ParseTokenAsInt(t,err);
1284 if(err) {
1285 ParseError(err,t);
1286 }
1287 return i;
1288}
1289
1290
1291
1292// ------------------------------------------------------------------------------------------------
1293// wrapper around ParseTokenAsInt64() with ParseError handling
1294int64_t ParseTokenAsInt64(const Token& t)
1295{
1296 const char* err;
1297 const int64_t i = ParseTokenAsInt64(t, err);
1298 if (err) {
1299 ParseError(err, t);
1300 }
1301 return i;
1302}
1303
1304} // !FBX
1305} // !Assimp
1306
1307#endif
1308