1 /*
2 bParse
3 Copyright (c) 2006-2009 Charlie C & Erwin Coumans  http://gamekit.googlecode.com
4 
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
10 
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15 #include "b3File.h"
16 #include "b3Common.h"
17 #include "b3Chunk.h"
18 #include "b3DNA.h"
19 #include <math.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include "b3Defines.h"
23 #include "Bullet3Serialize/Bullet2FileLoader/b3Serializer.h"
24 #include "Bullet3Common/b3AlignedAllocator.h"
25 #include "Bullet3Common/b3MinMax.h"
26 
27 #define B3_SIZEOFBLENDERHEADER 12
28 #define MAX_ARRAY_LENGTH 512
29 using namespace bParse;
30 #define MAX_STRLEN 1024
31 
getCleanName(const char * memName,char * buffer)32 const char *getCleanName(const char *memName, char *buffer)
33 {
34 	int slen = strlen(memName);
35 	assert(slen < MAX_STRLEN);
36 	slen = b3Min(slen, MAX_STRLEN);
37 	for (int i = 0; i < slen; i++)
38 	{
39 		if (memName[i] == ']' || memName[i] == '[')
40 		{
41 			buffer[i] = 0;  //'_';
42 		}
43 		else
44 		{
45 			buffer[i] = memName[i];
46 		}
47 	}
48 	buffer[slen] = 0;
49 	return buffer;
50 }
51 
52 // ----------------------------------------------------- //
bFile(const char * filename,const char headerString[7])53 bFile::bFile(const char *filename, const char headerString[7])
54 	: mOwnsBuffer(true),
55 	  mFileBuffer(0),
56 	  mFileLen(0),
57 	  mVersion(0),
58 	  mDataStart(0),
59 	  mFileDNA(0),
60 	  mMemoryDNA(0),
61 	  mFlags(FD_INVALID)
62 {
63 	for (int i = 0; i < 7; i++)
64 	{
65 		m_headerString[i] = headerString[i];
66 	}
67 
68 	FILE *fp = fopen(filename, "rb");
69 	if (fp)
70 	{
71 		fseek(fp, 0L, SEEK_END);
72 		mFileLen = ftell(fp);
73 		fseek(fp, 0L, SEEK_SET);
74 
75 		mFileBuffer = (char *)malloc(mFileLen + 1);
76 		int bytesRead;
77 		bytesRead = fread(mFileBuffer, mFileLen, 1, fp);
78 
79 		fclose(fp);
80 
81 		//
82 		parseHeader();
83 	}
84 }
85 
86 // ----------------------------------------------------- //
bFile(char * memoryBuffer,int len,const char headerString[7])87 bFile::bFile(char *memoryBuffer, int len, const char headerString[7])
88 	: mOwnsBuffer(false),
89 	  mFileBuffer(0),
90 	  mFileLen(0),
91 	  mVersion(0),
92 	  mDataStart(0),
93 	  mFileDNA(0),
94 	  mMemoryDNA(0),
95 	  mFlags(FD_INVALID)
96 {
97 	for (int i = 0; i < 7; i++)
98 	{
99 		m_headerString[i] = headerString[i];
100 	}
101 	mFileBuffer = memoryBuffer;
102 	mFileLen = len;
103 
104 	parseHeader();
105 }
106 
107 // ----------------------------------------------------- //
~bFile()108 bFile::~bFile()
109 {
110 	if (mOwnsBuffer && mFileBuffer)
111 	{
112 		free(mFileBuffer);
113 		mFileBuffer = 0;
114 	}
115 
116 	delete mMemoryDNA;
117 	delete mFileDNA;
118 }
119 
120 // ----------------------------------------------------- //
parseHeader()121 void bFile::parseHeader()
122 {
123 	if (!mFileLen || !mFileBuffer)
124 		return;
125 
126 	char *blenderBuf = mFileBuffer;
127 	char header[B3_SIZEOFBLENDERHEADER + 1];
128 	memcpy(header, blenderBuf, B3_SIZEOFBLENDERHEADER);
129 	header[B3_SIZEOFBLENDERHEADER] = '\0';
130 
131 	if (strncmp(header, m_headerString, 6) != 0)
132 	{
133 		memcpy(header, m_headerString, B3_SIZEOFBLENDERHEADER);
134 		return;
135 	}
136 
137 	if (header[6] == 'd')
138 	{
139 		mFlags |= FD_DOUBLE_PRECISION;
140 	}
141 
142 	char *ver = header + 9;
143 	mVersion = atoi(ver);
144 	if (mVersion <= 241)
145 	{
146 		//printf("Warning, %d not fully tested : <= 242\n", mVersion);
147 	}
148 
149 	int littleEndian = 1;
150 	littleEndian = ((char *)&littleEndian)[0];
151 
152 	// swap ptr sizes...
153 	if (header[7] == '-')
154 	{
155 		mFlags |= FD_FILE_64;
156 		if (!VOID_IS_8)
157 			mFlags |= FD_BITS_VARIES;
158 	}
159 	else if (VOID_IS_8)
160 		mFlags |= FD_BITS_VARIES;
161 
162 	// swap endian...
163 	if (header[8] == 'V')
164 	{
165 		if (littleEndian == 1)
166 			mFlags |= FD_ENDIAN_SWAP;
167 	}
168 	else if (littleEndian == 0)
169 		mFlags |= FD_ENDIAN_SWAP;
170 
171 	mFlags |= FD_OK;
172 }
173 
174 // ----------------------------------------------------- //
ok()175 bool bFile::ok()
176 {
177 	return (mFlags & FD_OK) != 0;
178 }
179 
180 // ----------------------------------------------------- //
parseInternal(int verboseMode,char * memDna,int memDnaLength)181 void bFile::parseInternal(int verboseMode, char *memDna, int memDnaLength)
182 {
183 	if ((mFlags & FD_OK) == 0)
184 		return;
185 
186 	char *blenderData = mFileBuffer;
187 	bChunkInd dna;
188 	dna.oldPtr = 0;
189 
190 	char *tempBuffer = blenderData;
191 	for (int i = 0; i < mFileLen; i++)
192 	{
193 		// looking for the data's starting position
194 		// and the start of SDNA decls
195 
196 		if (!mDataStart && strncmp(tempBuffer, "REND", 4) == 0)
197 			mDataStart = i;
198 
199 		if (strncmp(tempBuffer, "DNA1", 4) == 0)
200 		{
201 			// read the DNA1 block and extract SDNA
202 			if (getNextBlock(&dna, tempBuffer, mFlags) > 0)
203 			{
204 				if (strncmp((tempBuffer + ChunkUtils::getOffset(mFlags)), "SDNANAME", 8) == 0)
205 					dna.oldPtr = (tempBuffer + ChunkUtils::getOffset(mFlags));
206 				else
207 					dna.oldPtr = 0;
208 			}
209 			else
210 				dna.oldPtr = 0;
211 		}
212 		// Some Bullet files are missing the DNA1 block
213 		// In Blender it's DNA1 + ChunkUtils::getOffset() + SDNA + NAME
214 		// In Bullet tests its SDNA + NAME
215 		else if (strncmp(tempBuffer, "SDNANAME", 8) == 0)
216 		{
217 			dna.oldPtr = blenderData + i;
218 			dna.len = mFileLen - i;
219 
220 			// Also no REND block, so exit now.
221 			if (mVersion == 276) break;
222 		}
223 
224 		if (mDataStart && dna.oldPtr) break;
225 		tempBuffer++;
226 	}
227 	if (!dna.oldPtr || !dna.len)
228 	{
229 		//printf("Failed to find DNA1+SDNA pair\n");
230 		mFlags &= ~FD_OK;
231 		return;
232 	}
233 
234 	mFileDNA = new bDNA();
235 
236 	///mFileDNA->init will convert part of DNA file endianness to current CPU endianness if necessary
237 	mFileDNA->init((char *)dna.oldPtr, dna.len, (mFlags & FD_ENDIAN_SWAP) != 0);
238 
239 	if (mVersion == 276)
240 	{
241 		int i;
242 		for (i = 0; i < mFileDNA->getNumNames(); i++)
243 		{
244 			if (strcmp(mFileDNA->getName(i), "int") == 0)
245 			{
246 				mFlags |= FD_BROKEN_DNA;
247 			}
248 		}
249 		if ((mFlags & FD_BROKEN_DNA) != 0)
250 		{
251 			//printf("warning: fixing some broken DNA version\n");
252 		}
253 	}
254 
255 	if (verboseMode & FD_VERBOSE_DUMP_DNA_TYPE_DEFINITIONS)
256 		mFileDNA->dumpTypeDefinitions();
257 
258 	mMemoryDNA = new bDNA();
259 	int littleEndian = 1;
260 	littleEndian = ((char *)&littleEndian)[0];
261 
262 	mMemoryDNA->init(memDna, memDnaLength, littleEndian == 0);
263 
264 	///@todo we need a better version check, add version/sub version info from FileGlobal into memory DNA/header files
265 	if (mMemoryDNA->getNumNames() != mFileDNA->getNumNames())
266 	{
267 		mFlags |= FD_VERSION_VARIES;
268 		//printf ("Warning, file DNA is different than built in, performance is reduced. Best to re-export file with a matching version/platform");
269 	}
270 
271 	// as long as it kept up to date it will be ok!!
272 	if (mMemoryDNA->lessThan(mFileDNA))
273 	{
274 		//printf ("Warning, file DNA is newer than built in.");
275 	}
276 
277 	mFileDNA->initCmpFlags(mMemoryDNA);
278 
279 	parseData();
280 
281 	resolvePointers(verboseMode);
282 
283 	updateOldPointers();
284 }
285 
286 // ----------------------------------------------------- //
swap(char * head,bChunkInd & dataChunk,bool ignoreEndianFlag)287 void bFile::swap(char *head, bChunkInd &dataChunk, bool ignoreEndianFlag)
288 {
289 	char *data = head;
290 	short *strc = mFileDNA->getStruct(dataChunk.dna_nr);
291 
292 	const char s[] = "SoftBodyMaterialData";
293 	int szs = sizeof(s);
294 	if (strncmp((char *)&dataChunk.code, "ARAY", 4) == 0)
295 	{
296 		short *oldStruct = mFileDNA->getStruct(dataChunk.dna_nr);
297 		char *oldType = mFileDNA->getType(oldStruct[0]);
298 		if (strncmp(oldType, s, szs) == 0)
299 		{
300 			return;
301 		}
302 	}
303 
304 	int len = mFileDNA->getLength(strc[0]);
305 
306 	for (int i = 0; i < dataChunk.nr; i++)
307 	{
308 		swapStruct(dataChunk.dna_nr, data, ignoreEndianFlag);
309 		data += len;
310 	}
311 }
312 
swapLen(char * dataPtr)313 void bFile::swapLen(char *dataPtr)
314 {
315 	const bool VOID_IS_8 = ((sizeof(void *) == 8));
316 	if (VOID_IS_8)
317 	{
318 		if (mFlags & FD_BITS_VARIES)
319 		{
320 			bChunkPtr4 *c = (bChunkPtr4 *)dataPtr;
321 			if ((c->code & 0xFFFF) == 0)
322 				c->code >>= 16;
323 			B3_SWITCH_INT(c->len);
324 			B3_SWITCH_INT(c->dna_nr);
325 			B3_SWITCH_INT(c->nr);
326 		}
327 		else
328 		{
329 			bChunkPtr8 *c = (bChunkPtr8 *)dataPtr;
330 			if ((c->code & 0xFFFF) == 0)
331 				c->code >>= 16;
332 			B3_SWITCH_INT(c->len);
333 			B3_SWITCH_INT(c->dna_nr);
334 			B3_SWITCH_INT(c->nr);
335 		}
336 	}
337 	else
338 	{
339 		if (mFlags & FD_BITS_VARIES)
340 		{
341 			bChunkPtr8 *c = (bChunkPtr8 *)dataPtr;
342 			if ((c->code & 0xFFFF) == 0)
343 				c->code >>= 16;
344 			B3_SWITCH_INT(c->len);
345 			B3_SWITCH_INT(c->dna_nr);
346 			B3_SWITCH_INT(c->nr);
347 		}
348 		else
349 		{
350 			bChunkPtr4 *c = (bChunkPtr4 *)dataPtr;
351 			if ((c->code & 0xFFFF) == 0)
352 				c->code >>= 16;
353 			B3_SWITCH_INT(c->len);
354 
355 			B3_SWITCH_INT(c->dna_nr);
356 			B3_SWITCH_INT(c->nr);
357 		}
358 	}
359 }
360 
swapDNA(char * ptr)361 void bFile::swapDNA(char *ptr)
362 {
363 	bool swap = ((mFlags & FD_ENDIAN_SWAP) != 0);
364 
365 	char *data = &ptr[20];
366 	//	void bDNA::init(char *data, int len, bool swap)
367 	int *intPtr = 0;
368 	short *shtPtr = 0;
369 	char *cp = 0;
370 	int dataLen = 0;
371 	//long nr=0;
372 	intPtr = (int *)data;
373 
374 	/*
375 		SDNA (4 bytes) (magic number)
376 		NAME (4 bytes)
377 		<nr> (4 bytes) amount of names (int)
378 		<string>
379 		<string>
380 	*/
381 
382 	if (strncmp(data, "SDNA", 4) == 0)
383 	{
384 		// skip ++ NAME
385 		intPtr++;
386 		intPtr++;
387 	}
388 
389 	// Parse names
390 	if (swap)
391 		dataLen = ChunkUtils::swapInt(*intPtr);
392 	else
393 		dataLen = *intPtr;
394 
395 	*intPtr = ChunkUtils::swapInt(*intPtr);
396 	intPtr++;
397 
398 	cp = (char *)intPtr;
399 	int i;
400 	for (i = 0; i < dataLen; i++)
401 	{
402 		while (*cp) cp++;
403 		cp++;
404 	}
405 
406 	cp = b3AlignPointer(cp, 4);
407 
408 	/*
409 		TYPE (4 bytes)
410 		<nr> amount of types (int)
411 		<string>
412 		<string>
413 	*/
414 
415 	intPtr = (int *)cp;
416 	assert(strncmp(cp, "TYPE", 4) == 0);
417 	intPtr++;
418 
419 	if (swap)
420 		dataLen = ChunkUtils::swapInt(*intPtr);
421 	else
422 		dataLen = *intPtr;
423 
424 	*intPtr = ChunkUtils::swapInt(*intPtr);
425 
426 	intPtr++;
427 
428 	cp = (char *)intPtr;
429 	for (i = 0; i < dataLen; i++)
430 	{
431 		while (*cp) cp++;
432 		cp++;
433 	}
434 
435 	cp = b3AlignPointer(cp, 4);
436 
437 	/*
438 		TLEN (4 bytes)
439 		<len> (short) the lengths of types
440 		<len>
441 	*/
442 
443 	// Parse type lens
444 	intPtr = (int *)cp;
445 	assert(strncmp(cp, "TLEN", 4) == 0);
446 	intPtr++;
447 
448 	shtPtr = (short *)intPtr;
449 	for (i = 0; i < dataLen; i++, shtPtr++)
450 	{
451 		//??????if (swap)
452 		shtPtr[0] = ChunkUtils::swapShort(shtPtr[0]);
453 	}
454 
455 	if (dataLen & 1)
456 		shtPtr++;
457 
458 	/*
459 		STRC (4 bytes)
460 		<nr> amount of structs (int)
461 		<typenr>
462 		<nr_of_elems>
463 		<typenr>
464 		<namenr>
465 		<typenr>
466 		<namenr>
467 	*/
468 
469 	intPtr = (int *)shtPtr;
470 	cp = (char *)intPtr;
471 	assert(strncmp(cp, "STRC", 4) == 0);
472 	intPtr++;
473 
474 	if (swap)
475 		dataLen = ChunkUtils::swapInt(*intPtr);
476 	else
477 		dataLen = *intPtr;
478 
479 	*intPtr = ChunkUtils::swapInt(*intPtr);
480 
481 	intPtr++;
482 
483 	shtPtr = (short *)intPtr;
484 	for (i = 0; i < dataLen; i++)
485 	{
486 		//if (swap)
487 		{
488 			int len = shtPtr[1];
489 
490 			shtPtr[0] = ChunkUtils::swapShort(shtPtr[0]);
491 			shtPtr[1] = ChunkUtils::swapShort(shtPtr[1]);
492 
493 			shtPtr += 2;
494 
495 			for (int a = 0; a < len; a++, shtPtr += 2)
496 			{
497 				shtPtr[0] = ChunkUtils::swapShort(shtPtr[0]);
498 				shtPtr[1] = ChunkUtils::swapShort(shtPtr[1]);
499 			}
500 		}
501 		//		else
502 		//			shtPtr+= (2*shtPtr[1])+2;
503 	}
504 }
505 
writeFile(const char * fileName)506 void bFile::writeFile(const char *fileName)
507 {
508 	FILE *f = fopen(fileName, "wb");
509 	fwrite(mFileBuffer, 1, mFileLen, f);
510 	fclose(f);
511 }
512 
preSwap()513 void bFile::preSwap()
514 {
515 	//const bool brokenDNA = (mFlags&FD_BROKEN_DNA)!=0;
516 	//FD_ENDIAN_SWAP
517 	//byte 8 determines the endianness of the file, little (v) versus big (V)
518 	int littleEndian = 1;
519 	littleEndian = ((char *)&littleEndian)[0];
520 
521 	if (mFileBuffer[8] == 'V')
522 	{
523 		mFileBuffer[8] = 'v';
524 	}
525 	else
526 	{
527 		mFileBuffer[8] = 'V';
528 	}
529 
530 	mDataStart = 12;
531 
532 	char *dataPtr = mFileBuffer + mDataStart;
533 
534 	bChunkInd dataChunk;
535 	dataChunk.code = 0;
536 	bool ignoreEndianFlag = true;
537 
538 	//we always want to swap here
539 
540 	int seek = getNextBlock(&dataChunk, dataPtr, mFlags);
541 	//dataPtr += ChunkUtils::getOffset(mFlags);
542 	char *dataPtrHead = 0;
543 
544 	while (1)
545 	{
546 		// one behind
547 		if (dataChunk.code == B3_SDNA || dataChunk.code == B3_DNA1 || dataChunk.code == B3_TYPE || dataChunk.code == B3_TLEN || dataChunk.code == B3_STRC)
548 		{
549 			swapDNA(dataPtr);
550 			break;
551 		}
552 		else
553 		{
554 			//if (dataChunk.code == DNA1) break;
555 			dataPtrHead = dataPtr + ChunkUtils::getOffset(mFlags);
556 
557 			swapLen(dataPtr);
558 			if (dataChunk.dna_nr >= 0)
559 			{
560 				swap(dataPtrHead, dataChunk, ignoreEndianFlag);
561 			}
562 			else
563 			{
564 				//printf("unknown chunk\n");
565 			}
566 		}
567 
568 		// next please!
569 		dataPtr += seek;
570 
571 		seek = getNextBlock(&dataChunk, dataPtr, mFlags);
572 		if (seek < 0)
573 			break;
574 	}
575 
576 	if (mFlags & FD_ENDIAN_SWAP)
577 	{
578 		mFlags &= ~FD_ENDIAN_SWAP;
579 	}
580 	else
581 	{
582 		mFlags |= FD_ENDIAN_SWAP;
583 	}
584 }
585 
586 // ----------------------------------------------------- //
readStruct(char * head,bChunkInd & dataChunk)587 char *bFile::readStruct(char *head, bChunkInd &dataChunk)
588 {
589 	bool ignoreEndianFlag = false;
590 
591 	if (mFlags & FD_ENDIAN_SWAP)
592 		swap(head, dataChunk, ignoreEndianFlag);
593 
594 	if (!mFileDNA->flagEqual(dataChunk.dna_nr))
595 	{
596 		// Ouch! need to rebuild the struct
597 		short *oldStruct, *curStruct;
598 		char *oldType, *newType;
599 		int oldLen, curLen, reverseOld;
600 
601 		oldStruct = mFileDNA->getStruct(dataChunk.dna_nr);
602 		oldType = mFileDNA->getType(oldStruct[0]);
603 
604 		oldLen = mFileDNA->getLength(oldStruct[0]);
605 
606 		if ((mFlags & FD_BROKEN_DNA) != 0)
607 		{
608 			if ((strcmp(oldType, "b3QuantizedBvhNodeData") == 0) && oldLen == 20)
609 			{
610 				return 0;
611 			}
612 			if ((strcmp(oldType, "b3ShortIntIndexData") == 0))
613 			{
614 				int allocLen = 2;
615 				char *dataAlloc = new char[(dataChunk.nr * allocLen) + 1];
616 				memset(dataAlloc, 0, (dataChunk.nr * allocLen) + 1);
617 				short *dest = (short *)dataAlloc;
618 				const short *src = (short *)head;
619 				for (int i = 0; i < dataChunk.nr; i++)
620 				{
621 					dest[i] = src[i];
622 					if (mFlags & FD_ENDIAN_SWAP)
623 					{
624 						B3_SWITCH_SHORT(dest[i]);
625 					}
626 				}
627 				addDataBlock(dataAlloc);
628 				return dataAlloc;
629 			}
630 		}
631 
632 		///don't try to convert Link block data, just memcpy it. Other data can be converted.
633 		if (strcmp("Link", oldType) != 0)
634 		{
635 			reverseOld = mMemoryDNA->getReverseType(oldType);
636 
637 			if ((reverseOld != -1))
638 			{
639 				// make sure it's here
640 				//assert(reverseOld!= -1 && "getReverseType() returned -1, struct required!");
641 
642 				//
643 				curStruct = mMemoryDNA->getStruct(reverseOld);
644 				newType = mMemoryDNA->getType(curStruct[0]);
645 				curLen = mMemoryDNA->getLength(curStruct[0]);
646 
647 				// make sure it's the same
648 				assert((strcmp(oldType, newType) == 0) && "internal error, struct mismatch!");
649 
650 				// numBlocks * length
651 
652 				int allocLen = (curLen);
653 				char *dataAlloc = new char[(dataChunk.nr * allocLen) + 1];
654 				memset(dataAlloc, 0, (dataChunk.nr * allocLen));
655 
656 				// track allocated
657 				addDataBlock(dataAlloc);
658 
659 				char *cur = dataAlloc;
660 				char *old = head;
661 				for (int block = 0; block < dataChunk.nr; block++)
662 				{
663 					bool fixupPointers = true;
664 					parseStruct(cur, old, dataChunk.dna_nr, reverseOld, fixupPointers);
665 					mLibPointers.insert(old, (bStructHandle *)cur);
666 
667 					cur += curLen;
668 					old += oldLen;
669 				}
670 				return dataAlloc;
671 			}
672 		}
673 		else
674 		{
675 			//printf("Link found\n");
676 		}
677 	}
678 	else
679 	{
680 //#define DEBUG_EQUAL_STRUCTS
681 #ifdef DEBUG_EQUAL_STRUCTS
682 		short *oldStruct;
683 		char *oldType;
684 		oldStruct = mFileDNA->getStruct(dataChunk.dna_nr);
685 		oldType = mFileDNA->getType(oldStruct[0]);
686 		printf("%s equal structure, just memcpy\n", oldType);
687 #endif  //
688 	}
689 
690 	char *dataAlloc = new char[(dataChunk.len) + 1];
691 	memset(dataAlloc, 0, dataChunk.len + 1);
692 
693 	// track allocated
694 	addDataBlock(dataAlloc);
695 
696 	memcpy(dataAlloc, head, dataChunk.len);
697 	return dataAlloc;
698 }
699 
700 // ----------------------------------------------------- //
parseStruct(char * strcPtr,char * dtPtr,int old_dna,int new_dna,bool fixupPointers)701 void bFile::parseStruct(char *strcPtr, char *dtPtr, int old_dna, int new_dna, bool fixupPointers)
702 {
703 	if (old_dna == -1) return;
704 	if (new_dna == -1) return;
705 
706 	//disable this, because we need to fixup pointers/ListBase
707 	if (0)  //mFileDNA->flagEqual(old_dna))
708 	{
709 		short *strc = mFileDNA->getStruct(old_dna);
710 		int len = mFileDNA->getLength(strc[0]);
711 
712 		memcpy(strcPtr, dtPtr, len);
713 		return;
714 	}
715 
716 	// Ok, now build the struct
717 	char *memType, *memName, *cpc, *cpo;
718 	short *fileStruct, *filePtrOld, *memoryStruct, *firstStruct;
719 	int elementLength, size, revType, old_nr, new_nr, fpLen;
720 	short firstStructType;
721 
722 	// File to memory lookup
723 	memoryStruct = mMemoryDNA->getStruct(new_dna);
724 	fileStruct = mFileDNA->getStruct(old_dna);
725 	firstStruct = fileStruct;
726 
727 	filePtrOld = fileStruct;
728 	firstStructType = mMemoryDNA->getStruct(0)[0];
729 
730 	// Get number of elements
731 	elementLength = memoryStruct[1];
732 	memoryStruct += 2;
733 
734 	cpc = strcPtr;
735 	cpo = 0;
736 	for (int ele = 0; ele < elementLength; ele++, memoryStruct += 2)
737 	{
738 		memType = mMemoryDNA->getType(memoryStruct[0]);
739 		memName = mMemoryDNA->getName(memoryStruct[1]);
740 
741 		size = mMemoryDNA->getElementSize(memoryStruct[0], memoryStruct[1]);
742 		revType = mMemoryDNA->getReverseType(memoryStruct[0]);
743 
744 		if (revType != -1 && memoryStruct[0] >= firstStructType && memName[0] != '*')
745 		{
746 			cpo = getFileElement(firstStruct, memName, memType, dtPtr, &filePtrOld);
747 			if (cpo)
748 			{
749 				int arrayLen = mFileDNA->getArraySizeNew(filePtrOld[1]);
750 				old_nr = mFileDNA->getReverseType(memType);
751 				new_nr = revType;
752 				fpLen = mFileDNA->getElementSize(filePtrOld[0], filePtrOld[1]);
753 				if (arrayLen == 1)
754 				{
755 					parseStruct(cpc, cpo, old_nr, new_nr, fixupPointers);
756 				}
757 				else
758 				{
759 					char *tmpCpc = cpc;
760 					char *tmpCpo = cpo;
761 
762 					for (int i = 0; i < arrayLen; i++)
763 					{
764 						parseStruct(tmpCpc, tmpCpo, old_nr, new_nr, fixupPointers);
765 						tmpCpc += size / arrayLen;
766 						tmpCpo += fpLen / arrayLen;
767 					}
768 				}
769 				cpc += size;
770 				cpo += fpLen;
771 			}
772 			else
773 				cpc += size;
774 		}
775 		else
776 		{
777 			getMatchingFileDNA(fileStruct, memName, memType, cpc, dtPtr, fixupPointers);
778 			cpc += size;
779 		}
780 	}
781 }
782 
783 // ----------------------------------------------------- //
getElement(int arrayLen,const char * cur,const char * old,char * oldPtr,char * curData)784 static void getElement(int arrayLen, const char *cur, const char *old, char *oldPtr, char *curData)
785 {
786 #define b3GetEle(value, current, type, cast, size, ptr) \
787 	if (strcmp(current, type) == 0)                     \
788 	{                                                   \
789 		value = (*(cast *)ptr);                         \
790 		ptr += size;                                    \
791 	}
792 
793 #define b3SetEle(value, current, type, cast, size, ptr) \
794 	if (strcmp(current, type) == 0)                     \
795 	{                                                   \
796 		(*(cast *)ptr) = (cast)value;                   \
797 		ptr += size;                                    \
798 	}
799 	double value = 0.0;
800 
801 	for (int i = 0; i < arrayLen; i++)
802 	{
803 		b3GetEle(value, old, "char", char, sizeof(char), oldPtr);
804 		b3SetEle(value, cur, "char", char, sizeof(char), curData);
805 		b3GetEle(value, old, "short", short, sizeof(short), oldPtr);
806 		b3SetEle(value, cur, "short", short, sizeof(short), curData);
807 		b3GetEle(value, old, "ushort", unsigned short, sizeof(unsigned short), oldPtr);
808 		b3SetEle(value, cur, "ushort", unsigned short, sizeof(unsigned short), curData);
809 		b3GetEle(value, old, "int", int, sizeof(int), oldPtr);
810 		b3SetEle(value, cur, "int", int, sizeof(int), curData);
811 		b3GetEle(value, old, "long", int, sizeof(int), oldPtr);
812 		b3SetEle(value, cur, "long", int, sizeof(int), curData);
813 		b3GetEle(value, old, "float", float, sizeof(float), oldPtr);
814 		b3SetEle(value, cur, "float", float, sizeof(float), curData);
815 		b3GetEle(value, old, "double", double, sizeof(double), oldPtr);
816 		b3SetEle(value, cur, "double", double, sizeof(double), curData);
817 	}
818 }
819 
820 // ----------------------------------------------------- //
swapData(char * data,short type,int arraySize,bool ignoreEndianFlag)821 void bFile::swapData(char *data, short type, int arraySize, bool ignoreEndianFlag)
822 {
823 	if (ignoreEndianFlag || (mFlags & FD_ENDIAN_SWAP))
824 	{
825 		if (type == 2 || type == 3)
826 		{
827 			short *sp = (short *)data;
828 			for (int i = 0; i < arraySize; i++)
829 			{
830 				sp[0] = ChunkUtils::swapShort(sp[0]);
831 				sp++;
832 			}
833 		}
834 		if (type > 3 && type < 8)
835 		{
836 			char c;
837 			char *cp = data;
838 			for (int i = 0; i < arraySize; i++)
839 			{
840 				c = cp[0];
841 				cp[0] = cp[3];
842 				cp[3] = c;
843 				c = cp[1];
844 				cp[1] = cp[2];
845 				cp[2] = c;
846 				cp += 4;
847 			}
848 		}
849 	}
850 }
851 
safeSwapPtr(char * dst,const char * src)852 void bFile::safeSwapPtr(char *dst, const char *src)
853 {
854 	if (!src || !dst)
855 		return;
856 
857 	int ptrFile = mFileDNA->getPointerSize();
858 	int ptrMem = mMemoryDNA->getPointerSize();
859 
860 	if (ptrFile == ptrMem)
861 	{
862 		memcpy(dst, src, ptrMem);
863 	}
864 	else if (ptrMem == 4 && ptrFile == 8)
865 	{
866 		b3PointerUid *oldPtr = (b3PointerUid *)src;
867 		b3PointerUid *newPtr = (b3PointerUid *)dst;
868 
869 		if (oldPtr->m_uniqueIds[0] == oldPtr->m_uniqueIds[1])
870 		{
871 			//Bullet stores the 32bit unique ID in both upper and lower part of 64bit pointers
872 			//so it can be used to distinguish between .blend and .bullet
873 			newPtr->m_uniqueIds[0] = oldPtr->m_uniqueIds[0];
874 		}
875 		else
876 		{
877 			//deal with pointers the Blender .blend style way, see
878 			//readfile.c in the Blender source tree
879 			b3Long64 longValue = *((b3Long64 *)src);
880 			//endian swap for 64bit pointer otherwise truncation will fail due to trailing zeros
881 			if (mFlags & FD_ENDIAN_SWAP)
882 				B3_SWITCH_LONGINT(longValue);
883 			*((int *)dst) = (int)(longValue >> 3);
884 		}
885 	}
886 	else if (ptrMem == 8 && ptrFile == 4)
887 	{
888 		b3PointerUid *oldPtr = (b3PointerUid *)src;
889 		b3PointerUid *newPtr = (b3PointerUid *)dst;
890 		if (oldPtr->m_uniqueIds[0] == oldPtr->m_uniqueIds[1])
891 		{
892 			newPtr->m_uniqueIds[0] = oldPtr->m_uniqueIds[0];
893 			newPtr->m_uniqueIds[1] = 0;
894 		}
895 		else
896 		{
897 			*((b3Long64 *)dst) = *((int *)src);
898 		}
899 	}
900 	else
901 	{
902 		printf("%d %d\n", ptrFile, ptrMem);
903 		assert(0 && "Invalid pointer len");
904 	}
905 }
906 
907 // ----------------------------------------------------- //
getMatchingFileDNA(short * dna_addr,const char * lookupName,const char * lookupType,char * strcData,char * data,bool fixupPointers)908 void bFile::getMatchingFileDNA(short *dna_addr, const char *lookupName, const char *lookupType, char *strcData, char *data, bool fixupPointers)
909 {
910 	// find the matching memory dna data
911 	// to the file being loaded. Fill the
912 	// memory with the file data...
913 
914 	int len = dna_addr[1];
915 	dna_addr += 2;
916 
917 	for (int i = 0; i < len; i++, dna_addr += 2)
918 	{
919 		const char *type = mFileDNA->getType(dna_addr[0]);
920 		const char *name = mFileDNA->getName(dna_addr[1]);
921 
922 		int eleLen = mFileDNA->getElementSize(dna_addr[0], dna_addr[1]);
923 
924 		if ((mFlags & FD_BROKEN_DNA) != 0)
925 		{
926 			if ((strcmp(type, "short") == 0) && (strcmp(name, "int") == 0))
927 			{
928 				eleLen = 0;
929 			}
930 		}
931 
932 		if (strcmp(lookupName, name) == 0)
933 		{
934 			//int arrayLenold = mFileDNA->getArraySize((char*)name.c_str());
935 			int arrayLen = mFileDNA->getArraySizeNew(dna_addr[1]);
936 			//assert(arrayLenold == arrayLen);
937 
938 			if (name[0] == '*')
939 			{
940 				// cast pointers
941 				int ptrFile = mFileDNA->getPointerSize();
942 				int ptrMem = mMemoryDNA->getPointerSize();
943 				safeSwapPtr(strcData, data);
944 
945 				if (fixupPointers)
946 				{
947 					if (arrayLen > 1)
948 					{
949 						//void **sarray = (void**)strcData;
950 						//void **darray = (void**)data;
951 
952 						char *cpc, *cpo;
953 						cpc = (char *)strcData;
954 						cpo = (char *)data;
955 
956 						for (int a = 0; a < arrayLen; a++)
957 						{
958 							safeSwapPtr(cpc, cpo);
959 							m_pointerFixupArray.push_back(cpc);
960 							cpc += ptrMem;
961 							cpo += ptrFile;
962 						}
963 					}
964 					else
965 					{
966 						if (name[1] == '*')
967 							m_pointerPtrFixupArray.push_back(strcData);
968 						else
969 							m_pointerFixupArray.push_back(strcData);
970 					}
971 				}
972 				else
973 				{
974 					//					printf("skipped %s %s : %x\n",type.c_str(),name.c_str(),strcData);
975 				}
976 			}
977 
978 			else if (strcmp(type, lookupType) == 0)
979 				memcpy(strcData, data, eleLen);
980 			else
981 				getElement(arrayLen, lookupType, type, data, strcData);
982 
983 			// --
984 			return;
985 		}
986 		data += eleLen;
987 	}
988 }
989 
990 // ----------------------------------------------------- //
getFileElement(short * firstStruct,char * lookupName,char * lookupType,char * data,short ** foundPos)991 char *bFile::getFileElement(short *firstStruct, char *lookupName, char *lookupType, char *data, short **foundPos)
992 {
993 	short *old = firstStruct;  //mFileDNA->getStruct(old_nr);
994 	int elementLength = old[1];
995 	old += 2;
996 
997 	for (int i = 0; i < elementLength; i++, old += 2)
998 	{
999 		char *type = mFileDNA->getType(old[0]);
1000 		char *name = mFileDNA->getName(old[1]);
1001 		int len = mFileDNA->getElementSize(old[0], old[1]);
1002 
1003 		if (strcmp(lookupName, name) == 0)
1004 		{
1005 			if (strcmp(type, lookupType) == 0)
1006 			{
1007 				if (foundPos)
1008 					*foundPos = old;
1009 				return data;
1010 			}
1011 			return 0;
1012 		}
1013 		data += len;
1014 	}
1015 	return 0;
1016 }
1017 
1018 // ----------------------------------------------------- //
swapStruct(int dna_nr,char * data,bool ignoreEndianFlag)1019 void bFile::swapStruct(int dna_nr, char *data, bool ignoreEndianFlag)
1020 {
1021 	if (dna_nr == -1) return;
1022 
1023 	short *strc = mFileDNA->getStruct(dna_nr);
1024 	//short *firstStrc = strc;
1025 
1026 	int elementLen = strc[1];
1027 	strc += 2;
1028 
1029 	short first = mFileDNA->getStruct(0)[0];
1030 
1031 	char *buf = data;
1032 	for (int i = 0; i < elementLen; i++, strc += 2)
1033 	{
1034 		char *type = mFileDNA->getType(strc[0]);
1035 		char *name = mFileDNA->getName(strc[1]);
1036 
1037 		int size = mFileDNA->getElementSize(strc[0], strc[1]);
1038 		if (strc[0] >= first && name[0] != '*')
1039 		{
1040 			int old_nr = mFileDNA->getReverseType(type);
1041 			int arrayLen = mFileDNA->getArraySizeNew(strc[1]);
1042 			if (arrayLen == 1)
1043 			{
1044 				swapStruct(old_nr, buf, ignoreEndianFlag);
1045 			}
1046 			else
1047 			{
1048 				char *tmpBuf = buf;
1049 				for (int i = 0; i < arrayLen; i++)
1050 				{
1051 					swapStruct(old_nr, tmpBuf, ignoreEndianFlag);
1052 					tmpBuf += size / arrayLen;
1053 				}
1054 			}
1055 		}
1056 		else
1057 		{
1058 			//int arrayLenOld = mFileDNA->getArraySize(name);
1059 			int arrayLen = mFileDNA->getArraySizeNew(strc[1]);
1060 			//assert(arrayLenOld == arrayLen);
1061 			swapData(buf, strc[0], arrayLen, ignoreEndianFlag);
1062 		}
1063 		buf += size;
1064 	}
1065 }
1066 
resolvePointersMismatch()1067 void bFile::resolvePointersMismatch()
1068 {
1069 	//	printf("resolvePointersStructMismatch\n");
1070 
1071 	int i;
1072 
1073 	for (i = 0; i < m_pointerFixupArray.size(); i++)
1074 	{
1075 		char *cur = m_pointerFixupArray.at(i);
1076 		void **ptrptr = (void **)cur;
1077 		void *ptr = *ptrptr;
1078 		ptr = findLibPointer(ptr);
1079 		if (ptr)
1080 		{
1081 			//printf("Fixup pointer!\n");
1082 			*(ptrptr) = ptr;
1083 		}
1084 		else
1085 		{
1086 			//			printf("pointer not found: %x\n",cur);
1087 		}
1088 	}
1089 
1090 	for (i = 0; i < m_pointerPtrFixupArray.size(); i++)
1091 	{
1092 		char *cur = m_pointerPtrFixupArray.at(i);
1093 		void **ptrptr = (void **)cur;
1094 
1095 		bChunkInd *block = m_chunkPtrPtrMap.find(*ptrptr);
1096 		if (block)
1097 		{
1098 			int ptrMem = mMemoryDNA->getPointerSize();
1099 			int ptrFile = mFileDNA->getPointerSize();
1100 
1101 			int blockLen = block->len / ptrFile;
1102 
1103 			void *onptr = findLibPointer(*ptrptr);
1104 			if (onptr)
1105 			{
1106 				char *newPtr = new char[blockLen * ptrMem];
1107 				addDataBlock(newPtr);
1108 				memset(newPtr, 0, blockLen * ptrMem);
1109 
1110 				void **onarray = (void **)onptr;
1111 				char *oldPtr = (char *)onarray;
1112 
1113 				int p = 0;
1114 				while (blockLen-- > 0)
1115 				{
1116 					b3PointerUid dp = {{0}};
1117 					safeSwapPtr((char *)dp.m_uniqueIds, oldPtr);
1118 
1119 					void **tptr = (void **)(newPtr + p * ptrMem);
1120 					*tptr = findLibPointer(dp.m_ptr);
1121 
1122 					oldPtr += ptrFile;
1123 					++p;
1124 				}
1125 
1126 				*ptrptr = newPtr;
1127 			}
1128 		}
1129 	}
1130 }
1131 
1132 ///this loop only works fine if the Blender DNA structure of the file matches the headerfiles
resolvePointersChunk(const bChunkInd & dataChunk,int verboseMode)1133 void bFile::resolvePointersChunk(const bChunkInd &dataChunk, int verboseMode)
1134 {
1135 	bParse::bDNA *fileDna = mFileDNA ? mFileDNA : mMemoryDNA;
1136 
1137 	short int *oldStruct = fileDna->getStruct(dataChunk.dna_nr);
1138 	short oldLen = fileDna->getLength(oldStruct[0]);
1139 	//char* structType = fileDna->getType(oldStruct[0]);
1140 
1141 	char *cur = (char *)findLibPointer(dataChunk.oldPtr);
1142 	for (int block = 0; block < dataChunk.nr; block++)
1143 	{
1144 		resolvePointersStructRecursive(cur, dataChunk.dna_nr, verboseMode, 1);
1145 		cur += oldLen;
1146 	}
1147 }
1148 
resolvePointersStructRecursive(char * strcPtr,int dna_nr,int verboseMode,int recursion)1149 int bFile::resolvePointersStructRecursive(char *strcPtr, int dna_nr, int verboseMode, int recursion)
1150 {
1151 	bParse::bDNA *fileDna = mFileDNA ? mFileDNA : mMemoryDNA;
1152 
1153 	char *memType;
1154 	char *memName;
1155 	short firstStructType = fileDna->getStruct(0)[0];
1156 
1157 	char *elemPtr = strcPtr;
1158 
1159 	short int *oldStruct = fileDna->getStruct(dna_nr);
1160 
1161 	int elementLength = oldStruct[1];
1162 	oldStruct += 2;
1163 
1164 	int totalSize = 0;
1165 
1166 	for (int ele = 0; ele < elementLength; ele++, oldStruct += 2)
1167 	{
1168 		memType = fileDna->getType(oldStruct[0]);
1169 		memName = fileDna->getName(oldStruct[1]);
1170 
1171 		int arrayLen = fileDna->getArraySizeNew(oldStruct[1]);
1172 		if (memName[0] == '*')
1173 		{
1174 			if (arrayLen > 1)
1175 			{
1176 				void **array = (void **)elemPtr;
1177 				for (int a = 0; a < arrayLen; a++)
1178 				{
1179 					if (verboseMode & FD_VERBOSE_EXPORT_XML)
1180 					{
1181 						for (int i = 0; i < recursion; i++)
1182 						{
1183 							printf("  ");
1184 						}
1185 						//skip the *
1186 						printf("<%s type=\"pointer\"> ", &memName[1]);
1187 						printf("%p ", array[a]);
1188 						printf("</%s>\n", &memName[1]);
1189 					}
1190 
1191 					array[a] = findLibPointer(array[a]);
1192 				}
1193 			}
1194 			else
1195 			{
1196 				void **ptrptr = (void **)elemPtr;
1197 				void *ptr = *ptrptr;
1198 				if (verboseMode & FD_VERBOSE_EXPORT_XML)
1199 				{
1200 					for (int i = 0; i < recursion; i++)
1201 					{
1202 						printf("  ");
1203 					}
1204 					printf("<%s type=\"pointer\"> ", &memName[1]);
1205 					printf("%p ", ptr);
1206 					printf("</%s>\n", &memName[1]);
1207 				}
1208 				ptr = findLibPointer(ptr);
1209 
1210 				if (ptr)
1211 				{
1212 					//				printf("Fixup pointer at 0x%x from 0x%x to 0x%x!\n",ptrptr,*ptrptr,ptr);
1213 					*(ptrptr) = ptr;
1214 					if (memName[1] == '*' && ptrptr && *ptrptr)
1215 					{
1216 						// This	will only work if the given	**array	is continuous
1217 						void **array = (void **)*(ptrptr);
1218 						void *np = array[0];
1219 						int n = 0;
1220 						while (np)
1221 						{
1222 							np = findLibPointer(array[n]);
1223 							if (np) array[n] = np;
1224 							n++;
1225 						}
1226 					}
1227 				}
1228 				else
1229 				{
1230 					//				printf("Cannot fixup pointer at 0x%x from 0x%x to 0x%x!\n",ptrptr,*ptrptr,ptr);
1231 				}
1232 			}
1233 		}
1234 		else
1235 		{
1236 			int revType = fileDna->getReverseType(oldStruct[0]);
1237 			if (oldStruct[0] >= firstStructType)  //revType != -1 &&
1238 			{
1239 				char cleanName[MAX_STRLEN];
1240 				getCleanName(memName, cleanName);
1241 
1242 				int arrayLen = fileDna->getArraySizeNew(oldStruct[1]);
1243 				int byteOffset = 0;
1244 
1245 				if (verboseMode & FD_VERBOSE_EXPORT_XML)
1246 				{
1247 					for (int i = 0; i < recursion; i++)
1248 					{
1249 						printf("  ");
1250 					}
1251 
1252 					if (arrayLen > 1)
1253 					{
1254 						printf("<%s type=\"%s\" count=%d>\n", cleanName, memType, arrayLen);
1255 					}
1256 					else
1257 					{
1258 						printf("<%s type=\"%s\">\n", cleanName, memType);
1259 					}
1260 				}
1261 
1262 				for (int i = 0; i < arrayLen; i++)
1263 				{
1264 					byteOffset += resolvePointersStructRecursive(elemPtr + byteOffset, revType, verboseMode, recursion + 1);
1265 				}
1266 				if (verboseMode & FD_VERBOSE_EXPORT_XML)
1267 				{
1268 					for (int i = 0; i < recursion; i++)
1269 					{
1270 						printf("  ");
1271 					}
1272 					printf("</%s>\n", cleanName);
1273 				}
1274 			}
1275 			else
1276 			{
1277 				//export a simple type
1278 				if (verboseMode & FD_VERBOSE_EXPORT_XML)
1279 				{
1280 					if (arrayLen > MAX_ARRAY_LENGTH)
1281 					{
1282 						printf("too long\n");
1283 					}
1284 					else
1285 					{
1286 						//printf("%s %s\n",memType,memName);
1287 
1288 						bool isIntegerType = (strcmp(memType, "char") == 0) || (strcmp(memType, "int") == 0) || (strcmp(memType, "short") == 0);
1289 
1290 						if (isIntegerType)
1291 						{
1292 							const char *newtype = "int";
1293 							int dbarray[MAX_ARRAY_LENGTH];
1294 							int *dbPtr = 0;
1295 							char *tmp = elemPtr;
1296 							dbPtr = &dbarray[0];
1297 							if (dbPtr)
1298 							{
1299 								char cleanName[MAX_STRLEN];
1300 								getCleanName(memName, cleanName);
1301 
1302 								int i;
1303 								getElement(arrayLen, newtype, memType, tmp, (char *)dbPtr);
1304 								for (i = 0; i < recursion; i++)
1305 									printf("  ");
1306 								if (arrayLen == 1)
1307 									printf("<%s type=\"%s\">", cleanName, memType);
1308 								else
1309 									printf("<%s type=\"%s\" count=%d>", cleanName, memType, arrayLen);
1310 								for (i = 0; i < arrayLen; i++)
1311 									printf(" %d ", dbPtr[i]);
1312 								printf("</%s>\n", cleanName);
1313 							}
1314 						}
1315 						else
1316 						{
1317 							const char *newtype = "double";
1318 							double dbarray[MAX_ARRAY_LENGTH];
1319 							double *dbPtr = 0;
1320 							char *tmp = elemPtr;
1321 							dbPtr = &dbarray[0];
1322 							if (dbPtr)
1323 							{
1324 								int i;
1325 								getElement(arrayLen, newtype, memType, tmp, (char *)dbPtr);
1326 								for (i = 0; i < recursion; i++)
1327 									printf("  ");
1328 								char cleanName[MAX_STRLEN];
1329 								getCleanName(memName, cleanName);
1330 
1331 								if (arrayLen == 1)
1332 								{
1333 									printf("<%s type=\"%s\">", memName, memType);
1334 								}
1335 								else
1336 								{
1337 									printf("<%s type=\"%s\" count=%d>", cleanName, memType, arrayLen);
1338 								}
1339 								for (i = 0; i < arrayLen; i++)
1340 									printf(" %f ", dbPtr[i]);
1341 								printf("</%s>\n", cleanName);
1342 							}
1343 						}
1344 					}
1345 				}
1346 			}
1347 		}
1348 
1349 		int size = fileDna->getElementSize(oldStruct[0], oldStruct[1]);
1350 		totalSize += size;
1351 		elemPtr += size;
1352 	}
1353 
1354 	return totalSize;
1355 }
1356 
1357 ///Resolve pointers replaces the original pointers in structures, and linked lists by the new in-memory structures
resolvePointers(int verboseMode)1358 void bFile::resolvePointers(int verboseMode)
1359 {
1360 	bParse::bDNA *fileDna = mFileDNA ? mFileDNA : mMemoryDNA;
1361 
1362 	//char *dataPtr = mFileBuffer+mDataStart;
1363 
1364 	if (1)  //mFlags & (FD_BITS_VARIES | FD_VERSION_VARIES))
1365 	{
1366 		resolvePointersMismatch();
1367 	}
1368 
1369 	{
1370 		if (verboseMode & FD_VERBOSE_EXPORT_XML)
1371 		{
1372 			printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1373 			int numitems = m_chunks.size();
1374 			printf("<bullet_physics version=%d itemcount = %d>\n", b3GetVersion(), numitems);
1375 		}
1376 		for (int i = 0; i < m_chunks.size(); i++)
1377 		{
1378 			const bChunkInd &dataChunk = m_chunks.at(i);
1379 
1380 			if (!mFileDNA || fileDna->flagEqual(dataChunk.dna_nr))
1381 			{
1382 				//dataChunk.len
1383 				short int *oldStruct = fileDna->getStruct(dataChunk.dna_nr);
1384 				char *oldType = fileDna->getType(oldStruct[0]);
1385 
1386 				if (verboseMode & FD_VERBOSE_EXPORT_XML)
1387 					printf(" <%s pointer=%p>\n", oldType, dataChunk.oldPtr);
1388 
1389 				resolvePointersChunk(dataChunk, verboseMode);
1390 
1391 				if (verboseMode & FD_VERBOSE_EXPORT_XML)
1392 					printf(" </%s>\n", oldType);
1393 			}
1394 			else
1395 			{
1396 				//printf("skipping mStruct\n");
1397 			}
1398 		}
1399 		if (verboseMode & FD_VERBOSE_EXPORT_XML)
1400 		{
1401 			printf("</bullet_physics>\n");
1402 		}
1403 	}
1404 }
1405 
1406 // ----------------------------------------------------- //
findLibPointer(void * ptr)1407 void *bFile::findLibPointer(void *ptr)
1408 {
1409 	bStructHandle **ptrptr = getLibPointers().find(ptr);
1410 	if (ptrptr)
1411 		return *ptrptr;
1412 	return 0;
1413 }
1414 
updateOldPointers()1415 void bFile::updateOldPointers()
1416 {
1417 	int i;
1418 
1419 	for (i = 0; i < m_chunks.size(); i++)
1420 	{
1421 		bChunkInd &dataChunk = m_chunks[i];
1422 		dataChunk.oldPtr = findLibPointer(dataChunk.oldPtr);
1423 	}
1424 }
dumpChunks(bParse::bDNA * dna)1425 void bFile::dumpChunks(bParse::bDNA *dna)
1426 {
1427 	int i;
1428 
1429 	for (i = 0; i < m_chunks.size(); i++)
1430 	{
1431 		bChunkInd &dataChunk = m_chunks[i];
1432 		char *codeptr = (char *)&dataChunk.code;
1433 		char codestr[5] = {codeptr[0], codeptr[1], codeptr[2], codeptr[3], 0};
1434 
1435 		short *newStruct = dna->getStruct(dataChunk.dna_nr);
1436 		char *typeName = dna->getType(newStruct[0]);
1437 		printf("%3d: %s  ", i, typeName);
1438 
1439 		printf("code=%s  ", codestr);
1440 
1441 		printf("ptr=%p  ", dataChunk.oldPtr);
1442 		printf("len=%d  ", dataChunk.len);
1443 		printf("nr=%d  ", dataChunk.nr);
1444 		if (dataChunk.nr != 1)
1445 		{
1446 			printf("not 1\n");
1447 		}
1448 		printf("\n");
1449 	}
1450 
1451 #if 0
1452 	IDFinderData ifd;
1453 	ifd.success = 0;
1454 	ifd.IDname = NULL;
1455 	ifd.just_print_it = 1;
1456 	for (i=0; i<bf->m_blocks.size(); ++i)
1457 	{
1458 		BlendBlock* bb = bf->m_blocks[i];
1459 		printf("tag='%s'\tptr=%p\ttype=%s\t[%4d]",		bb->tag, bb,bf->types[bb->type_index].name,bb->m_array_entries_.size());
1460 		block_ID_finder(bb, bf, &ifd);
1461 		printf("\n");
1462 	}
1463 #endif
1464 }
1465 
writeChunks(FILE * fp,bool fixupPointers)1466 void bFile::writeChunks(FILE *fp, bool fixupPointers)
1467 {
1468 	bParse::bDNA *fileDna = mFileDNA ? mFileDNA : mMemoryDNA;
1469 
1470 	for (int i = 0; i < m_chunks.size(); i++)
1471 	{
1472 		bChunkInd &dataChunk = m_chunks.at(i);
1473 
1474 		// Ouch! need to rebuild the struct
1475 		short *oldStruct, *curStruct;
1476 		char *oldType, *newType;
1477 		int oldLen, curLen, reverseOld;
1478 
1479 		oldStruct = fileDna->getStruct(dataChunk.dna_nr);
1480 		oldType = fileDna->getType(oldStruct[0]);
1481 		oldLen = fileDna->getLength(oldStruct[0]);
1482 		///don't try to convert Link block data, just memcpy it. Other data can be converted.
1483 		reverseOld = mMemoryDNA->getReverseType(oldType);
1484 
1485 		if ((reverseOld != -1))
1486 		{
1487 			// make sure it's here
1488 			//assert(reverseOld!= -1 && "getReverseType() returned -1, struct required!");
1489 			//
1490 			curStruct = mMemoryDNA->getStruct(reverseOld);
1491 			newType = mMemoryDNA->getType(curStruct[0]);
1492 			// make sure it's the same
1493 			assert((strcmp(oldType, newType) == 0) && "internal error, struct mismatch!");
1494 
1495 			curLen = mMemoryDNA->getLength(curStruct[0]);
1496 			dataChunk.dna_nr = reverseOld;
1497 			if (strcmp("Link", oldType) != 0)
1498 			{
1499 				dataChunk.len = curLen * dataChunk.nr;
1500 			}
1501 			else
1502 			{
1503 				//				printf("keep length of link = %d\n",dataChunk.len);
1504 			}
1505 
1506 			//write the structure header
1507 			fwrite(&dataChunk, sizeof(bChunkInd), 1, fp);
1508 
1509 			short int *curStruct1;
1510 			curStruct1 = mMemoryDNA->getStruct(dataChunk.dna_nr);
1511 			assert(curStruct1 == curStruct);
1512 
1513 			char *cur = fixupPointers ? (char *)findLibPointer(dataChunk.oldPtr) : (char *)dataChunk.oldPtr;
1514 
1515 			//write the actual contents of the structure(s)
1516 			fwrite(cur, dataChunk.len, 1, fp);
1517 		}
1518 		else
1519 		{
1520 			printf("serious error, struct mismatch: don't write\n");
1521 		}
1522 	}
1523 }
1524 
1525 // ----------------------------------------------------- //
getNextBlock(bChunkInd * dataChunk,const char * dataPtr,const int flags)1526 int bFile::getNextBlock(bChunkInd *dataChunk, const char *dataPtr, const int flags)
1527 {
1528 	bool swap = false;
1529 	bool varies = false;
1530 
1531 	if (flags & FD_ENDIAN_SWAP)
1532 		swap = true;
1533 	if (flags & FD_BITS_VARIES)
1534 		varies = true;
1535 
1536 	if (VOID_IS_8)
1537 	{
1538 		if (varies)
1539 		{
1540 			bChunkPtr4 head;
1541 			memcpy(&head, dataPtr, sizeof(bChunkPtr4));
1542 
1543 			bChunkPtr8 chunk;
1544 
1545 			chunk.code = head.code;
1546 			chunk.len = head.len;
1547 			chunk.m_uniqueInts[0] = head.m_uniqueInt;
1548 			chunk.m_uniqueInts[1] = 0;
1549 			chunk.dna_nr = head.dna_nr;
1550 			chunk.nr = head.nr;
1551 
1552 			if (swap)
1553 			{
1554 				if ((chunk.code & 0xFFFF) == 0)
1555 					chunk.code >>= 16;
1556 
1557 				B3_SWITCH_INT(chunk.len);
1558 				B3_SWITCH_INT(chunk.dna_nr);
1559 				B3_SWITCH_INT(chunk.nr);
1560 			}
1561 
1562 			memcpy(dataChunk, &chunk, sizeof(bChunkInd));
1563 		}
1564 		else
1565 		{
1566 			bChunkPtr8 c;
1567 			memcpy(&c, dataPtr, sizeof(bChunkPtr8));
1568 
1569 			if (swap)
1570 			{
1571 				if ((c.code & 0xFFFF) == 0)
1572 					c.code >>= 16;
1573 
1574 				B3_SWITCH_INT(c.len);
1575 				B3_SWITCH_INT(c.dna_nr);
1576 				B3_SWITCH_INT(c.nr);
1577 			}
1578 
1579 			memcpy(dataChunk, &c, sizeof(bChunkInd));
1580 		}
1581 	}
1582 	else
1583 	{
1584 		if (varies)
1585 		{
1586 			bChunkPtr8 head;
1587 			memcpy(&head, dataPtr, sizeof(bChunkPtr8));
1588 
1589 			bChunkPtr4 chunk;
1590 			chunk.code = head.code;
1591 			chunk.len = head.len;
1592 
1593 			if (head.m_uniqueInts[0] == head.m_uniqueInts[1])
1594 			{
1595 				chunk.m_uniqueInt = head.m_uniqueInts[0];
1596 			}
1597 			else
1598 			{
1599 				b3Long64 oldPtr = 0;
1600 				memcpy(&oldPtr, &head.m_uniqueInts[0], 8);
1601 				if (swap)
1602 					B3_SWITCH_LONGINT(oldPtr);
1603 				chunk.m_uniqueInt = (int)(oldPtr >> 3);
1604 			}
1605 
1606 			chunk.dna_nr = head.dna_nr;
1607 			chunk.nr = head.nr;
1608 
1609 			if (swap)
1610 			{
1611 				if ((chunk.code & 0xFFFF) == 0)
1612 					chunk.code >>= 16;
1613 
1614 				B3_SWITCH_INT(chunk.len);
1615 				B3_SWITCH_INT(chunk.dna_nr);
1616 				B3_SWITCH_INT(chunk.nr);
1617 			}
1618 
1619 			memcpy(dataChunk, &chunk, sizeof(bChunkInd));
1620 		}
1621 		else
1622 		{
1623 			bChunkPtr4 c;
1624 			memcpy(&c, dataPtr, sizeof(bChunkPtr4));
1625 
1626 			if (swap)
1627 			{
1628 				if ((c.code & 0xFFFF) == 0)
1629 					c.code >>= 16;
1630 
1631 				B3_SWITCH_INT(c.len);
1632 				B3_SWITCH_INT(c.dna_nr);
1633 				B3_SWITCH_INT(c.nr);
1634 			}
1635 			memcpy(dataChunk, &c, sizeof(bChunkInd));
1636 		}
1637 	}
1638 
1639 	if (dataChunk->len < 0)
1640 		return -1;
1641 
1642 #if 0
1643 	print ("----------");
1644 	print (dataChunk->code);
1645 	print (dataChunk->len);
1646 	print (dataChunk->old);
1647 	print (dataChunk->dna_nr);
1648 	print (dataChunk->nr);
1649 #endif
1650 	return (dataChunk->len + ChunkUtils::getOffset(flags));
1651 }
1652 
1653 //eof
1654