add support for serialization/writing DNA on big endian machines

fix for swapping endianness for nested array of structures
This commit is contained in:
erwin.coumans
2010-01-28 10:56:38 +00:00
parent 0814473528
commit ae0e78efd8
3 changed files with 442 additions and 389 deletions

View File

@@ -341,6 +341,7 @@ static int name_is_array(char* name, int* dim1, int* dim2) {
// ----------------------------------------------------- // // ----------------------------------------------------- //
void bDNA::init(char *data, int len, bool swap) void bDNA::init(char *data, int len, bool swap)
{ {
printf("swap = %d\n",swap);
int *intPtr=0;short *shtPtr=0; int *intPtr=0;short *shtPtr=0;
char *cp = 0;int dataLen =0;long nr=0; char *cp = 0;int dataLen =0;long nr=0;
intPtr = (int*)data; intPtr = (int*)data;

View File

@@ -140,8 +140,11 @@ void bFile::parseHeader()
else if (VOID_IS_8) mFlags |= FD_BITS_VARIES; else if (VOID_IS_8) mFlags |= FD_BITS_VARIES;
// swap endian... // swap endian...
if (header[8]=='V' && littleEndian ==1) if (header[8]=='V')
mFlags |= FD_ENDIAN_SWAP; {
if (littleEndian ==1)
mFlags |= FD_ENDIAN_SWAP;
}
else else
if (littleEndian==0) if (littleEndian==0)
mFlags |= FD_ENDIAN_SWAP; mFlags |= FD_ENDIAN_SWAP;
@@ -199,7 +202,10 @@ void bFile::parseInternal(bool verboseDumpAllTypes, char* memDna,int memDnaLengt
} }
mMemoryDNA = new bDNA(); mMemoryDNA = new bDNA();
mMemoryDNA->init(memDna,memDnaLength); int littleEndian= 1;
littleEndian= ((char*)&littleEndian)[0];
mMemoryDNA->init(memDna,memDnaLength,littleEndian==0);
@@ -644,14 +650,25 @@ void bFile::swapStruct(int dna_nr, char *data)
if (strc[0] >= first && name[0]!='*') if (strc[0] >= first && name[0]!='*')
{ {
int old_nr = mFileDNA->getReverseType(type); int old_nr = mFileDNA->getReverseType(type);
swapStruct(old_nr,buf); int arrayLen = mFileDNA->getArraySizeNew(strc[1]);
if (arrayLen==1)
{
swapStruct(old_nr,buf);
} else
{
char* tmpBuf = buf;
for (int i=0;i<arrayLen;i++)
{
swapStruct(old_nr,tmpBuf);
tmpBuf+=size/arrayLen;
}
}
} }
else else
{ {
//int arrayLenOld = mFileDNA->getArraySize(name); //int arrayLenOld = mFileDNA->getArraySize(name);
int arrayLen = mFileDNA->getArraySizeNew(strc[1]); int arrayLen = mFileDNA->getArraySizeNew(strc[1]);
//assert(arrayLenOld == arrayLen); //assert(arrayLenOld == arrayLen);
swapData(buf, strc[0], arrayLen); swapData(buf, strc[0], arrayLen);
} }
buf+=size; buf+=size;

View File

@@ -1,384 +1,419 @@
/* /*
Bullet Continuous Collision Detection and Physics Library Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty. This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely, including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions: subject to the following restrictions:
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. 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.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#ifndef BT_SERIALIZER_H #ifndef BT_SERIALIZER_H
#define BT_SERIALIZER_H #define BT_SERIALIZER_H
#include "btScalar.h" // has definitions like SIMD_FORCE_INLINE #include "btScalar.h" // has definitions like SIMD_FORCE_INLINE
#include "btStackAlloc.h" #include "btStackAlloc.h"
#include "btHashMap.h" #include "btHashMap.h"
#include <memory.h> #include <memory.h>
#include <string.h> #include <string.h>
///only the 32bit versions for now ///only the 32bit versions for now
extern unsigned char sBulletDNAstr[]; extern unsigned char sBulletDNAstr[];
extern int sBulletDNAlen; extern int sBulletDNAlen;
extern unsigned char sBulletDNAstr64[]; extern unsigned char sBulletDNAstr64[];
extern int sBulletDNAlen64; extern int sBulletDNAlen64;
class btChunk class btChunk
{ {
public: public:
int m_chunkCode; int m_chunkCode;
int m_length; int m_length;
void *m_oldPtr; void *m_oldPtr;
int m_dna_nr; int m_dna_nr;
int m_number; int m_number;
}; };
class btSerializer class btSerializer
{ {
public: public:
virtual const unsigned char* getBufferPointer() const = 0; virtual const unsigned char* getBufferPointer() const = 0;
virtual int getCurrentBufferSize() const = 0; virtual int getCurrentBufferSize() const = 0;
virtual btChunk* allocate(size_t size, int numElements) = 0; virtual btChunk* allocate(size_t size, int numElements) = 0;
virtual void finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr) const = 0; virtual void finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr) const = 0;
virtual void startSerialization() = 0; virtual void startSerialization() = 0;
virtual void finishSerialization() = 0; virtual void finishSerialization() = 0;
}; };
#define BT_HEADER_LENGTH 12 #define BT_HEADER_LENGTH 12
#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) #if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
# define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) ) # define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) )
#else #else
# define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) ) # define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) )
#endif #endif
#define BT_COLLISIONOBJECT_CODE MAKE_ID('C','O','B','J') #define BT_COLLISIONOBJECT_CODE MAKE_ID('C','O','B','J')
#define BT_RIGIDBODY_CODE MAKE_ID('R','B','D','Y') #define BT_RIGIDBODY_CODE MAKE_ID('R','B','D','Y')
#define BT_CONSTRAINT_CODE MAKE_ID('C','O','N','S') #define BT_CONSTRAINT_CODE MAKE_ID('C','O','N','S')
#define BT_BOXSHAPE_CODE MAKE_ID('B','O','X','S') #define BT_BOXSHAPE_CODE MAKE_ID('B','O','X','S')
#define BT_SHAPE_CODE MAKE_ID('S','H','A','P') #define BT_SHAPE_CODE MAKE_ID('S','H','A','P')
#define BT_ARRAY_CODE MAKE_ID('A','R','A','Y') #define BT_ARRAY_CODE MAKE_ID('A','R','A','Y')
class btDefaultSerializer : public btSerializer
{
class btDefaultSerializer : public btSerializer
{
btAlignedObjectArray<char*> mTypes;
btAlignedObjectArray<short*> mStructs;
btAlignedObjectArray<short> mTlens; btAlignedObjectArray<char*> mTypes;
btHashMap<btHashInt, int> mStructReverse; btAlignedObjectArray<short*> mStructs;
btHashMap<btHashString,int> mTypeLookup; btAlignedObjectArray<short> mTlens;
btHashMap<btHashInt, int> mStructReverse;
btAlignedObjectArray<btChunk*> m_chunkPtrs; btHashMap<btHashString,int> mTypeLookup;
int m_totalSize; btAlignedObjectArray<btChunk*> m_chunkPtrs;
unsigned char* m_buffer;
int m_currentSize; int m_totalSize;
unsigned char* m_buffer;
protected: int m_currentSize;
void writeDNA() protected:
{
unsigned char* dnaTarget = m_buffer+m_currentSize; void writeDNA()
memcpy(dnaTarget,m_dna,m_dnaLength); {
m_currentSize += m_dnaLength; unsigned char* dnaTarget = m_buffer+m_currentSize;
} memcpy(dnaTarget,m_dna,m_dnaLength);
m_currentSize += m_dnaLength;
int getReverseType(const char *type) const }
{
int getReverseType(const char *type) const
btHashString key(type); {
const int* valuePtr = mTypeLookup.find(key);
if (valuePtr) btHashString key(type);
return *valuePtr; const int* valuePtr = mTypeLookup.find(key);
if (valuePtr)
return -1; return *valuePtr;
}
return -1;
void initDNA(const char* bdna,int dnalen) }
{
///was already initialized void initDNA(const char* bdnaOrg,int dnalen)
if (m_dna) {
return; ///was already initialized
if (m_dna)
m_dna = btAlignedAlloc(dnalen,16); return;
memcpy(m_dna,bdna,dnalen);
m_dnaLength = dnalen; int littleEndian= 1;
littleEndian= ((char*)&littleEndian)[0];
int *intPtr=0;short *shtPtr=0;
char *cp = 0;int dataLen =0;long nr=0;
intPtr = (int*)bdna; m_dna = btAlignedAlloc(dnalen,16);
memcpy(m_dna,bdnaOrg,dnalen);
/* m_dnaLength = dnalen;
SDNA (4 bytes) (magic number)
NAME (4 bytes) int *intPtr=0;
<nr> (4 bytes) amount of names (int) short *shtPtr=0;
<string> char *cp = 0;int dataLen =0;long nr=0;
<string> intPtr = (int*)m_dna;
*/
/*
if (strncmp((const char*)bdna, "SDNA", 4)==0) SDNA (4 bytes) (magic number)
{ NAME (4 bytes)
// skip ++ NAME <nr> (4 bytes) amount of names (int)
intPtr++; intPtr++; <string>
} <string>
*/
// Parse names
if (strncmp((const char*)m_dna, "SDNA", 4)==0)
dataLen = *intPtr; {
intPtr++; // skip ++ NAME
intPtr++; intPtr++;
cp = (char*)intPtr; }
for (int i=0; i<dataLen; i++)
{ // Parse names
if (!littleEndian)
while (*cp)cp++; *intPtr = btSwapEndian(*intPtr);
cp++;
} dataLen = *intPtr;
{
nr= (long)cp; intPtr++;
long mask=3;
nr= ((nr+3)&~3)-nr; cp = (char*)intPtr;
while (nr--) for (int i=0; i<dataLen; i++)
{ {
cp++;
} while (*cp)cp++;
} cp++;
}
/* {
TYPE (4 bytes) nr= (long)cp;
<nr> amount of types (int) long mask=3;
<string> nr= ((nr+3)&~3)-nr;
<string> while (nr--)
*/ {
cp++;
intPtr = (int*)cp; }
assert(strncmp(cp, "TYPE", 4)==0); intPtr++; }
dataLen = *intPtr; /*
intPtr++; TYPE (4 bytes)
<nr> amount of types (int)
cp = (char*)intPtr; <string>
for (int i=0; i<dataLen; i++) <string>
{ */
mTypes.push_back(cp);
while (*cp)cp++; intPtr = (int*)cp;
cp++; assert(strncmp(cp, "TYPE", 4)==0); intPtr++;
}
if (!littleEndian)
{ *intPtr = btSwapEndian(*intPtr);
nr= (long)cp;
long mask=3; dataLen = *intPtr;
nr= ((nr+3)&~3)-nr; intPtr++;
while (nr--)
{ cp = (char*)intPtr;
cp++; for (int i=0; i<dataLen; i++)
} {
} mTypes.push_back(cp);
while (*cp)cp++;
cp++;
/* }
TLEN (4 bytes)
<len> (short) the lengths of types {
<len> nr= (long)cp;
*/ long mask=3;
nr= ((nr+3)&~3)-nr;
// Parse type lens while (nr--)
intPtr = (int*)cp; {
assert(strncmp(cp, "TLEN", 4)==0); intPtr++; cp++;
}
dataLen = (int)mTypes.size(); }
shtPtr = (short*)intPtr;
for (int i=0; i<dataLen; i++, shtPtr++) /*
{ TLEN (4 bytes)
mTlens.push_back(shtPtr[0]); <len> (short) the lengths of types
} <len>
*/
if (dataLen & 1) shtPtr++;
// Parse type lens
/* intPtr = (int*)cp;
STRC (4 bytes) assert(strncmp(cp, "TLEN", 4)==0); intPtr++;
<nr> amount of structs (int)
<typenr> dataLen = (int)mTypes.size();
<nr_of_elems>
<typenr> shtPtr = (short*)intPtr;
<namenr> for (int i=0; i<dataLen; i++, shtPtr++)
<typenr> {
<namenr> if (!littleEndian)
*/ shtPtr[0] = btSwapEndian(shtPtr[0]);
mTlens.push_back(shtPtr[0]);
intPtr = (int*)shtPtr; }
cp = (char*)intPtr;
assert(strncmp(cp, "STRC", 4)==0); intPtr++; if (dataLen & 1) shtPtr++;
dataLen = *intPtr; /*
intPtr++; STRC (4 bytes)
<nr> amount of structs (int)
<typenr>
shtPtr = (short*)intPtr; <nr_of_elems>
for (int i=0; i<dataLen; i++) <typenr>
{ <namenr>
mStructs.push_back (shtPtr); <typenr>
shtPtr+= (2*shtPtr[1])+2; <namenr>
} */
// build reverse lookups intPtr = (int*)shtPtr;
for (int i=0; i<(int)mStructs.size(); i++) cp = (char*)intPtr;
{ assert(strncmp(cp, "STRC", 4)==0); intPtr++;
short *strc = mStructs.at(i);
mStructReverse.insert(strc[0], i); if (!littleEndian)
mTypeLookup.insert(btHashString(mTypes[strc[0]]),i); *intPtr = btSwapEndian(*intPtr);
} dataLen = *intPtr ;
} intPtr++;
public:
shtPtr = (short*)intPtr;
for (int i=0; i<dataLen; i++)
void* m_dna; {
int m_dnaLength; mStructs.push_back (shtPtr);
if (!littleEndian)
btDefaultSerializer(int totalSize) {
:m_totalSize(totalSize), shtPtr[0]= btSwapEndian(shtPtr[0]);
m_currentSize(0), shtPtr[1]= btSwapEndian(shtPtr[1]);
m_dna(0),
m_dnaLength(0) int len = shtPtr[1];
{ shtPtr+= 2;
m_buffer = (unsigned char*)btAlignedAlloc(totalSize, 16);
for (int a=0; a<len; a++, shtPtr+=2)
const bool VOID_IS_8 = ((sizeof(void*)==8)); {
shtPtr[0]= btSwapEndian(shtPtr[0]);
if (VOID_IS_8) shtPtr[1]= btSwapEndian(shtPtr[1]);
{ }
//#if _WIN64
initDNA((const char*)sBulletDNAstr64,sBulletDNAlen64); } else
//#else {
// btAssert(0); shtPtr+= (2*shtPtr[1])+2;
//#endif }
} else }
{
//#ifndef _WIN64 // build reverse lookups
initDNA((const char*)sBulletDNAstr,sBulletDNAlen); for (int i=0; i<(int)mStructs.size(); i++)
//#else {
// btAssert(0); short *strc = mStructs.at(i);
//#endif mStructReverse.insert(strc[0], i);
} mTypeLookup.insert(btHashString(mTypes[strc[0]]),i);
}
} }
virtual ~btDefaultSerializer() public:
{
btAlignedFree(m_buffer);
} void* m_dna;
int m_dnaLength;
virtual void startSerialization()
{
m_currentSize = BT_HEADER_LENGTH; btDefaultSerializer(int totalSize)
:m_totalSize(totalSize),
#ifdef BT_USE_DOUBLE_PRECISION m_currentSize(0),
memcpy(m_buffer, "BULLETd", 7); m_dna(0),
#else m_dnaLength(0)
memcpy(m_buffer, "BULLETf", 7); {
#endif //BT_USE_DOUBLE_PRECISION m_buffer = (unsigned char*)btAlignedAlloc(totalSize, 16);
int littleEndian= 1; const bool VOID_IS_8 = ((sizeof(void*)==8));
littleEndian= ((char*)&littleEndian)[0];
if (VOID_IS_8)
if (sizeof(void*)==8) {
{ //#if _WIN64
m_buffer[7] = '-'; initDNA((const char*)sBulletDNAstr64,sBulletDNAlen64);
} else //#else
{ // btAssert(0);
m_buffer[7] = '_'; //#endif
} } else
{
if (littleEndian) //#ifndef _WIN64
{ initDNA((const char*)sBulletDNAstr,sBulletDNAlen);
m_buffer[8]='v'; //#else
} else // btAssert(0);
{ //#endif
m_buffer[8]='V'; }
}
}
m_buffer[9] = '2'; virtual ~btDefaultSerializer()
m_buffer[10] = '7'; {
m_buffer[11] = '6'; btAlignedFree(m_buffer);
}
} virtual void startSerialization()
{
virtual void finishSerialization() m_currentSize = BT_HEADER_LENGTH;
{
writeDNA(); #ifdef BT_USE_DOUBLE_PRECISION
} memcpy(m_buffer, "BULLETd", 7);
#else
memcpy(m_buffer, "BULLETf", 7);
virtual const unsigned char* getBufferPointer() const #endif //BT_USE_DOUBLE_PRECISION
{
return m_buffer; int littleEndian= 1;
} littleEndian= ((char*)&littleEndian)[0];
virtual int getCurrentBufferSize() const if (sizeof(void*)==8)
{ {
return m_currentSize; m_buffer[7] = '-';
} } else
{
virtual void finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr) const m_buffer[7] = '_';
{ }
chunk->m_dna_nr = getReverseType(structType);
if (littleEndian)
chunk->m_chunkCode = chunkCode; {
chunk->m_oldPtr = oldPtr; m_buffer[8]='v';
} } else
{
m_buffer[8]='V';
}
virtual btChunk* allocate(size_t size, int numElements) m_buffer[9] = '2';
{ m_buffer[10] = '7';
m_buffer[11] = '6';
unsigned char* ptr = m_buffer+m_currentSize;
m_currentSize += int(size)*numElements+sizeof(btChunk);
}
unsigned char* data = ptr + sizeof(btChunk);
virtual void finishSerialization()
btChunk* chunk = (btChunk*)ptr; {
chunk->m_chunkCode = 0; writeDNA();
chunk->m_oldPtr = data; }
chunk->m_length = int(size)*numElements;
chunk->m_number = numElements;
virtual const unsigned char* getBufferPointer() const
m_chunkPtrs.push_back(chunk); {
return m_buffer;
return chunk; }
}
virtual int getCurrentBufferSize() const
{
return m_currentSize;
}
};
virtual void finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr) const
{
#endif //BT_SERIALIZER_H chunk->m_dna_nr = getReverseType(structType);
chunk->m_chunkCode = chunkCode;
chunk->m_oldPtr = oldPtr;
}
virtual btChunk* allocate(size_t size, int numElements)
{
unsigned char* ptr = m_buffer+m_currentSize;
m_currentSize += int(size)*numElements+sizeof(btChunk);
unsigned char* data = ptr + sizeof(btChunk);
btChunk* chunk = (btChunk*)ptr;
chunk->m_chunkCode = 0;
chunk->m_oldPtr = data;
chunk->m_length = int(size)*numElements;
chunk->m_number = numElements;
m_chunkPtrs.push_back(chunk);
return chunk;
}
};
#endif //BT_SERIALIZER_H