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