[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-physics / third-party / bullet3 / src / Bullet3Serialize / Bullet2FileLoader / b3File.cpp
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
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 // ----------------------------------------------------- //
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 // ----------------------------------------------------- //
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 // ----------------------------------------------------- //
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 // ----------------------------------------------------- //
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 // ----------------------------------------------------- //
175 bool bFile::ok()
176 {
177         return (mFlags & FD_OK) != 0;
178 }
179
180 // ----------------------------------------------------- //
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 // ----------------------------------------------------- //
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
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
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
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
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 // ----------------------------------------------------- //
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 // ----------------------------------------------------- //
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 // ----------------------------------------------------- //
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 // ----------------------------------------------------- //
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
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 // ----------------------------------------------------- //
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 // ----------------------------------------------------- //
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 // ----------------------------------------------------- //
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
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
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
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
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 // ----------------------------------------------------- //
1407 void *bFile::findLibPointer(void *ptr)
1408 {
1409         bStructHandle **ptrptr = getLibPointers().find(ptr);
1410         if (ptrptr)
1411                 return *ptrptr;
1412         return 0;
1413 }
1414
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 }
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
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 // ----------------------------------------------------- //
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