Home | History | Annotate | Download | only in BulletFileLoader
      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