Imported Upstream version 2.81
[platform/upstream/libbullet.git] / Extras / Serialize / BulletFileLoader / bDNA.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 <assert.h>
16
17 #include "bDNA.h"
18 #include "bChunk.h"
19 #include <string.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22
23 //this define will force traversal of structures, to check backward (and forward) compatibility
24 //#define TEST_BACKWARD_FORWARD_COMPATIBILITY
25
26
27 using namespace bParse;
28
29
30 // ----------------------------------------------------- //
31 bDNA::bDNA()
32         :       mPtrLen(0)
33 {
34         // --
35 }
36
37 // ----------------------------------------------------- //
38 bDNA::~bDNA()
39 {
40         // --
41 }
42
43 // ----------------------------------------------------- //
44 bool bDNA::lessThan(bDNA *file)
45 {
46         return ( m_Names.size() < file->m_Names.size());
47 }
48
49 // ----------------------------------------------------- //
50 char *bDNA::getName(int ind)
51 {
52         assert(ind <= (int)m_Names.size());
53         return m_Names[ind].m_name;
54 }
55
56
57 // ----------------------------------------------------- //
58 char *bDNA::getType(int ind)
59 {
60         assert(ind<=  (int)mTypes.size());
61         return mTypes[ind];
62 }
63
64
65 // ----------------------------------------------------- //
66 short *bDNA::getStruct(int ind)
67 {
68         assert(ind <=  (int)mStructs.size());
69         return mStructs[ind];
70 }
71
72
73 // ----------------------------------------------------- //
74 short bDNA::getLength(int ind)
75 {
76         assert(ind <=  (int)mTlens.size());
77         return mTlens[ind];
78 }
79
80
81 // ----------------------------------------------------- //
82 int bDNA::getReverseType(short type)
83 {
84
85         int* intPtr = mStructReverse.find(type);
86         if (intPtr)
87                 return *intPtr;
88
89         return -1;
90 }
91
92 // ----------------------------------------------------- //
93 int bDNA::getReverseType(const char *type)
94 {
95
96         btHashString key(type);
97         int* valuePtr = mTypeLookup.find(key);
98         if (valuePtr)
99                 return *valuePtr;
100         
101         return -1;
102 }
103
104 // ----------------------------------------------------- //
105 int bDNA::getNumStructs()
106 {
107         return (int)mStructs.size();
108 }
109
110 // ----------------------------------------------------- //
111 bool bDNA::flagNotEqual(int dna_nr)
112 {
113         assert(dna_nr <=        (int)mCMPFlags.size());
114         return mCMPFlags[dna_nr] == FDF_STRUCT_NEQU;
115 }
116
117 // ----------------------------------------------------- //
118 bool bDNA::flagEqual(int dna_nr)
119 {
120         assert(dna_nr <=        (int)mCMPFlags.size());
121         int flag = mCMPFlags[dna_nr];
122         return  flag == FDF_STRUCT_EQU;
123 }
124
125 // ----------------------------------------------------- //
126 bool bDNA::flagNone(int dna_nr)
127 {
128         assert(dna_nr <=        (int)mCMPFlags.size());
129         return mCMPFlags[dna_nr] == FDF_NONE;
130 }
131
132 // ----------------------------------------------------- //
133 int bDNA::getPointerSize()
134 {
135         return mPtrLen;
136 }
137
138 // ----------------------------------------------------- //
139 void bDNA::initRecurseCmpFlags(int iter)
140 {
141         // iter is FDF_STRUCT_NEQU
142
143         short *oldStrc = mStructs[iter];
144         short type = oldStrc[0];
145
146         for (int i=0; i<(int)mStructs.size(); i++)
147         {
148                 if (i != iter && mCMPFlags[i] == FDF_STRUCT_EQU )
149                 {
150                         short *curStruct = mStructs[i];
151                         int eleLen = curStruct[1];
152                         curStruct+=2;
153
154                         for (int j=0; j<eleLen; j++, curStruct+=2)
155                         {
156                                 if (curStruct[0] == type)
157                                 {
158                                         //char *name = m_Names[curStruct[1]].m_name;
159                                         //if (name[0] != '*')
160                                         if (m_Names[curStruct[1]].m_isPointer)
161                                         {
162                                                 mCMPFlags[i] = FDF_STRUCT_NEQU;
163                                                 initRecurseCmpFlags(i);
164                                         }
165                                 }
166                         }
167                 }
168         }
169 }
170
171 // ----------------------------------------------------- //
172 void bDNA::initCmpFlags(bDNA *memDNA)
173 {
174
175     // compare the file to memory
176         // this ptr should be the file data
177
178
179         assert(!m_Names.size() == 0 && "SDNA empty!");
180         mCMPFlags.resize(mStructs.size(), FDF_NONE);
181
182
183
184         int i;
185         for ( i=0; i<(int)mStructs.size(); i++)
186         {
187                 short *oldStruct = mStructs[i];
188
189                 int oldLookup = getReverseType(oldStruct[0]);
190                 if (oldLookup == -1)
191                 {
192                         mCMPFlags[i] = FDF_NONE;
193                         continue;
194                 }
195                 //char* typeName = mTypes[oldStruct[0]];
196
197 //#define SLOW_FORWARD_COMPATIBLE 1
198 #ifdef SLOW_FORWARD_COMPATIBLE
199                 char* typeName = mTypes[oldLookup];
200                 int newLookup = memDNA->getReverseType(typeName);
201                 if (newLookup == -1)
202                 {
203                         mCMPFlags[i] = FDF_NONE;
204                         continue;
205                 }
206                 short *curStruct = memDNA->mStructs[newLookup];
207 #else
208                 // memory for file
209
210                 if (oldLookup < memDNA->mStructs.size())
211                 {
212                         short *curStruct = memDNA->mStructs[oldLookup];
213 #endif  
214         
215                 
216
217                         // rebuild...
218                         mCMPFlags[i] = FDF_STRUCT_NEQU;
219
220 #ifndef TEST_BACKWARD_FORWARD_COMPATIBILITY
221
222                         if (curStruct[1] == oldStruct[1])
223                         {
224                                 // type len same ...
225                                 if (mTlens[oldStruct[0]] == memDNA->mTlens[curStruct[0]])
226                                 {
227                                         bool isSame = true;
228                                         int elementLength = oldStruct[1];
229
230
231                                         curStruct+=2;
232                                         oldStruct+=2;
233
234
235                                         for (int j=0; j<elementLength; j++, curStruct+=2, oldStruct+=2)
236                                         {
237                                                 // type the same
238                                                 //const char* typeFileDNA = mTypes[oldStruct[0]];
239                                                 //const char* typeMemDNA = mTypes[curStruct[0]];
240                                                 if (strcmp(mTypes[oldStruct[0]], memDNA->mTypes[curStruct[0]])!=0)
241                                                 {
242                                                         isSame=false;
243                                                         break;
244                                                 }
245
246                                                 // name the same
247                                                 if (strcmp(m_Names[oldStruct[1]].m_name, memDNA->m_Names[curStruct[1]].m_name)!=0)
248                                                 {
249                                                         isSame=false;
250                                                         break;
251                                                 }
252                                         }
253                                         // flag valid ==
254                                         if (isSame)
255                                                 mCMPFlags[i] = FDF_STRUCT_EQU;
256                                 }
257                         }
258 #endif
259                 }
260         }
261
262
263
264
265
266         // recurse in
267         for ( i=0; i<(int)mStructs.size(); i++)
268         {
269                 if (mCMPFlags[i] == FDF_STRUCT_NEQU)
270                         initRecurseCmpFlags(i);
271         }
272 }
273
274
275
276
277 static int name_is_array(char* name, int* dim1, int* dim2) {
278         int len = strlen(name);
279         /*fprintf(stderr,"[%s]",name);*/
280         /*if (len >= 1) {
281         if (name[len-1] != ']')
282         return 1;
283         }
284         return 0;*/
285         char *bp;
286         int num;
287         if (dim1) {
288                 *dim1 = 1;
289         }
290         if (dim2) {
291                 *dim2 = 1;
292         }
293         bp = strchr(name, '[');
294         if (!bp) {
295                 return 0;
296         }
297         num = 0;
298         while (++bp < name+len-1) {
299                 const char c = *bp;
300                 if (c == ']') {
301                         break;
302                 }
303                 if (c <= '9' && c >= '0') {
304                         num *= 10;
305                         num += (c - '0');
306                 } else {
307                         printf("array parse error.\n");
308                         return 0;
309                 }
310         }
311         if (dim2) {
312                 *dim2 = num;
313         }
314
315         /* find second dim, if any. */
316         bp = strchr(bp, '[');
317         if (!bp) {
318                 return 1; /* at least we got the first dim. */
319         }
320         num = 0;
321         while (++bp < name+len-1) {
322                 const char c = *bp;
323                 if (c == ']') {
324                         break;
325                 }
326                 if (c <= '9' && c >= '0') {
327                         num *= 10;
328                         num += (c - '0');
329                 } else {
330                         printf("array2 parse error.\n");
331                         return 1;
332                 }
333         }
334         if (dim1) {
335                 if (dim2) {
336                         *dim1 = *dim2;
337                         *dim2 = num;
338                 } else {
339                         *dim1 = num;
340                 }
341         }
342
343         return 1;
344 }
345
346
347 // ----------------------------------------------------- //
348 void bDNA::init(char *data, int len, bool swap)
349 {
350         int *intPtr=0;short *shtPtr=0;
351         char *cp = 0;int dataLen =0;long nr=0;
352         intPtr = (int*)data;
353
354         /*
355                 SDNA (4 bytes) (magic number)
356                 NAME (4 bytes)
357                 <nr> (4 bytes) amount of names (int)
358                 <string>
359                 <string>
360         */
361
362         if (strncmp(data, "SDNA", 4)==0)
363         {
364                 // skip ++ NAME
365                 intPtr++; intPtr++;
366         }
367
368
369
370         // Parse names
371         if (swap) dataLen = ChunkUtils::swapInt(*intPtr);
372         else      dataLen = *intPtr;
373         intPtr++;
374
375         cp = (char*)intPtr;
376         int i;
377         for ( i=0; i<dataLen; i++)
378         {
379                 bNameInfo info;
380                 info.m_name = cp;
381                 info.m_isPointer = (info.m_name[0] == '*') || (info.m_name[1] == '*');
382                 name_is_array(info.m_name,&info.m_dim0,&info.m_dim1);
383                 m_Names.push_back(info);
384                 while (*cp)cp++;
385                 cp++;
386         }
387
388         
389         {
390                 nr= (long)cp;
391         //long mask=3;
392                 nr= ((nr+3)&~3)-nr;
393                 while (nr--)
394                 {
395                         cp++;
396                 }
397         }
398
399
400         /*
401                 TYPE (4 bytes)
402                 <nr> amount of types (int)
403                 <string>
404                 <string>
405         */
406
407         intPtr = (int*)cp;
408         assert(strncmp(cp, "TYPE", 4)==0); intPtr++;
409
410         if (swap) dataLen = ChunkUtils::swapInt(*intPtr);
411         else      dataLen = *intPtr;
412         intPtr++;
413
414         cp = (char*)intPtr;
415         for ( i=0; i<dataLen; i++)
416         {
417                 mTypes.push_back(cp);
418                 while (*cp)cp++;
419                 cp++;
420         }
421
422 {
423                 nr= (long)cp;
424         //      long mask=3;
425                 nr= ((nr+3)&~3)-nr;
426                 while (nr--)
427                 {
428                         cp++;
429                 }
430         }
431
432
433         /*
434                 TLEN (4 bytes)
435                 <len> (short) the lengths of types
436                 <len>
437         */
438
439         // Parse type lens
440         intPtr = (int*)cp;
441         assert(strncmp(cp, "TLEN", 4)==0); intPtr++;
442
443         dataLen = (int)mTypes.size();
444
445         shtPtr = (short*)intPtr;
446         for ( i=0; i<dataLen; i++, shtPtr++)
447         {
448                 if (swap)
449                         shtPtr[0] = ChunkUtils::swapShort(shtPtr[0]);
450                 mTlens.push_back(shtPtr[0]);
451         }
452
453         if (dataLen & 1) shtPtr++;
454
455         /*
456                 STRC (4 bytes)
457                 <nr> amount of structs (int)
458                 <typenr>
459                 <nr_of_elems>
460                 <typenr>
461                 <namenr>
462                 <typenr>
463                 <namenr>
464         */
465
466         intPtr = (int*)shtPtr;
467         cp = (char*)intPtr;
468         assert(strncmp(cp, "STRC", 4)==0); intPtr++;
469
470         if (swap) dataLen = ChunkUtils::swapInt(*intPtr);
471         else      dataLen = *intPtr;
472         intPtr++;
473
474
475         shtPtr = (short*)intPtr;
476         for ( i=0; i<dataLen; i++)
477         {
478                 mStructs.push_back (shtPtr);
479                 if (swap)
480                 {
481                         shtPtr[0]= ChunkUtils::swapShort(shtPtr[0]);
482                         shtPtr[1]= ChunkUtils::swapShort(shtPtr[1]);
483
484                         int len = shtPtr[1];
485                         shtPtr+= 2;
486
487                         for (int a=0; a<len; a++, shtPtr+=2)
488                         {
489                                 shtPtr[0]= ChunkUtils::swapShort(shtPtr[0]);
490                                 shtPtr[1]= ChunkUtils::swapShort(shtPtr[1]);
491                         }
492                 }
493                 else
494                         shtPtr+= (2*shtPtr[1])+2;
495         }
496
497
498         // build reverse lookups
499         for ( i=0; i<(int)mStructs.size(); i++)
500         {
501                 short *strc = mStructs.at(i);
502                 if (!mPtrLen && strcmp(mTypes[strc[0]],"ListBase")==0)
503                 {
504                         mPtrLen = mTlens[strc[0]]/2;
505                 }
506
507                 mStructReverse.insert(strc[0], i);
508                 mTypeLookup.insert(btHashString(mTypes[strc[0]]),i);
509         }
510 }
511
512
513 // ----------------------------------------------------- //
514 int bDNA::getArraySize(char* string)
515 {
516         int ret = 1;
517         int len = strlen(string);
518
519         
520         char* next = 0;
521         for (int i=0; i<len; i++)
522         {
523                 char c = string[i];
524
525                 if (c == '[')
526                         next = &string[i+1];
527                 else if (c==']')
528                         if (next)
529                                 ret *= atoi(next);
530         }
531
532 //      print (string << ' ' << ret);
533         return ret;
534 }
535
536
537 void bDNA::dumpTypeDefinitions()
538 {
539         int i;
540
541         int numTypes = mTypes.size();
542         
543         for (i=0;i<numTypes;i++)
544         {
545
546         }
547
548         for ( i=0; i<(int)mStructs.size(); i++)
549         {
550                 int totalBytes=0;
551                 short *oldStruct = mStructs[i];
552
553                 int oldLookup = getReverseType(oldStruct[0]);
554                 if (oldLookup == -1)
555                 {
556                         mCMPFlags[i] = FDF_NONE;
557                         continue;
558                 }
559
560                 short* newStruct = mStructs[oldLookup];
561                 char* typeName = mTypes[newStruct[0]];
562                 printf("%3d: %s ",i,typeName);
563                 
564                 //char *name = mNames[oldStruct[1]];
565                 int len = oldStruct[1];
566                 printf(" (%d fields) ",len);
567                 oldStruct+=2;
568
569                 printf("{");
570                 int j;
571                 for (j=0; j<len; ++j,oldStruct+=2) {
572                         const char* name = m_Names[oldStruct[1]].m_name;
573                         printf("%s %s", mTypes[oldStruct[0]],name);
574                         int elemNumBytes= 0;
575                         int arrayDimensions = getArraySizeNew(oldStruct[1]);
576
577                         if (m_Names[oldStruct[1]].m_isPointer)
578                         {
579                                 elemNumBytes = VOID_IS_8 ? 8 : 4;
580                         } else
581                         {
582                                 elemNumBytes = getLength(oldStruct[0]);
583                         }
584                         printf(" /* %d bytes */",elemNumBytes*arrayDimensions);
585                         
586                         if (j == len-1) {
587                                 printf(";}");
588                         } else {
589                                 printf("; ");
590                         }
591                         totalBytes+=elemNumBytes*arrayDimensions;
592                 }
593                 printf("\ntotalBytes=%d\n\n",totalBytes);
594
595         }
596         
597
598
599 #if 0
600         /* dump out display of types and their sizes */
601         for (i=0; i<bf->types_count; ++i) {
602                 /* if (!bf->types[i].is_struct)*/
603                 {
604                         printf("%3d: sizeof(%s%s)=%d",
605                                 i,
606                                 bf->types[i].is_struct ? "struct " : "atomic ",
607                                 bf->types[i].name, bf->types[i].size);
608                         if (bf->types[i].is_struct) {
609                                 int j;
610                                 printf(", %d fields: { ", bf->types[i].fieldtypes_count);
611                                 for (j=0; j<bf->types[i].fieldtypes_count; ++j) {
612                                         printf("%s %s",
613                                                 bf->types[bf->types[i].fieldtypes[j]].name,
614                                                 bf->names[bf->types[i].fieldnames[j]]);
615                                         if (j == bf->types[i].fieldtypes_count-1) {
616                                                 printf(";}");
617                                         } else {
618                                                 printf("; ");
619                                         }
620                                 }
621                         }
622                         printf("\n\n");
623
624                 }
625         }
626 #endif
627
628 }
629
630
631
632
633 //eof
634
635