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