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