Replaced $Id$ and $Header$ keywords with $Revision-Id$ Deleted $Log$ keywords and any log messages
1830 lines
43 KiB
C++
1830 lines
43 KiB
C++
/*************************************************************************\
|
|
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
|
* National Laboratory.
|
|
* Copyright (c) 2002 The Regents of the University of California, as
|
|
* Operator of Los Alamos National Laboratory.
|
|
* EPICS BASE Versions 3.13.7
|
|
* and higher are distributed subject to a Software License Agreement found
|
|
* in file LICENSE that is included with this distribution.
|
|
\*************************************************************************/
|
|
// Author: Jim Kowalkowski
|
|
// Date: 2/96
|
|
//
|
|
// $Revision-Id$
|
|
//
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
|
|
#include <string>
|
|
#include <stdexcept>
|
|
|
|
#define epicsExportSharedSymbols
|
|
#include "gdd.h"
|
|
|
|
gdd_NEWDEL_NEW(gdd)
|
|
gdd_NEWDEL_DEL(gdd)
|
|
gdd_NEWDEL_STAT(gdd)
|
|
|
|
epicsMutex * gdd::pGlobalMutex;
|
|
|
|
static epicsThreadOnceId gddOnce = EPICS_THREAD_ONCE_INIT;
|
|
|
|
class gddFlattenDestructor : public gddDestructor
|
|
{
|
|
public:
|
|
gddFlattenDestructor(void) { }
|
|
gddFlattenDestructor(void* user_arg):gddDestructor(user_arg) { }
|
|
void run(void*);
|
|
};
|
|
|
|
class gddContainerCleaner : public gddDestructor
|
|
{
|
|
public:
|
|
gddContainerCleaner(void) { }
|
|
gddContainerCleaner(void* user_arg):gddDestructor(user_arg) { }
|
|
void run(void*);
|
|
};
|
|
|
|
void gddFlattenDestructor::run(void*)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void gddContainerCleaner::run(void* v)
|
|
{
|
|
gddContainer* cdd = (gddContainer*)v;
|
|
int tot = cdd->total();
|
|
int i;
|
|
for(i=0;i<tot;i++) cdd->remove(0);
|
|
}
|
|
|
|
//
|
|
// special gddDestructor guarantees same form of new and delete
|
|
//
|
|
class gddAitUint8Destructor: public gddDestructor {
|
|
virtual void run (void *);
|
|
};
|
|
|
|
//
|
|
// special gddDestructor guarantees same form of new and delete
|
|
//
|
|
class gddAitStringDestructor: public gddDestructor {
|
|
virtual void run (void *);
|
|
};
|
|
|
|
// --------------------------The gdd functions-------------------------
|
|
|
|
extern "C" void gddStaticInit ( void * p )
|
|
{
|
|
epicsMutex * * pMutex = static_cast < epicsMutex * * > ( p );
|
|
*pMutex = new epicsMutex ();
|
|
}
|
|
|
|
gdd::gdd(int app, aitEnum prim, int dimen)
|
|
{
|
|
init(app,prim,dimen);
|
|
}
|
|
|
|
gdd::gdd(int app, aitEnum prim, int dimen, aitUint32* val)
|
|
{
|
|
init(app,prim,dimen);
|
|
for(int i=0;i<dimen;i++) bounds[i].set(0,val[i]);
|
|
}
|
|
|
|
void gdd::init(int app, aitEnum prim, int dimen)
|
|
{
|
|
epicsThreadOnce ( & gddOnce, gddStaticInit, & gdd::pGlobalMutex );
|
|
setApplType(app);
|
|
//
|
|
// joh - we intentionally dont call setPrimType()
|
|
// here because the assumption is that init() is only
|
|
// called from the constructor, and we dont want
|
|
// to destroy a non-existent string if the uninitialized
|
|
// prim type is a string
|
|
//
|
|
this->prim_type = prim;
|
|
dim=(aitUint8)dimen;
|
|
destruct=NULL;
|
|
ref_cnt=1;
|
|
flags=0;
|
|
bounds=NULL;
|
|
setStatSevr(0u,0u);
|
|
|
|
if(dim)
|
|
{
|
|
switch(dim)
|
|
{
|
|
case 1: bounds=(gddBounds*)new gddBounds1D; bounds->set(0,0); break;
|
|
case 2: bounds=(gddBounds*)new gddBounds2D; break;
|
|
case 3: bounds=(gddBounds*)new gddBounds3D; break;
|
|
default: bounds=(gddBounds*)new gddBounds[dim]; break;
|
|
}
|
|
memset ( & this->data, '\0', sizeof ( this->data ) );
|
|
}
|
|
else if(primitiveType()==aitEnumString)
|
|
{
|
|
aitString* str=(aitString*)dataAddress();
|
|
str->init();
|
|
}
|
|
else if (primitiveType()==aitEnumFixedString)
|
|
{
|
|
this->data.FString = new aitFixedString;
|
|
memset ( this->data.FString, '\0', sizeof(aitFixedString) );
|
|
}
|
|
else {
|
|
memset ( & this->data, '\0', sizeof ( this->data ) );
|
|
}
|
|
}
|
|
|
|
gdd::gdd(gdd* dd)
|
|
{
|
|
//
|
|
// added this because the "copy()" below bombs
|
|
// if the GDD isnt initialized
|
|
// joh - 4-23-99
|
|
//
|
|
this->init (dd->appl_type, dd->primitiveType(), dd->dimension());
|
|
|
|
copyInfo(dd);
|
|
}
|
|
|
|
gdd::~gdd(void)
|
|
{
|
|
gdd* dd;
|
|
gdd* temp;
|
|
|
|
// fprintf(stderr,"A gdd is really being deleted %8.8x!!\n",this);
|
|
|
|
if(isContainer())
|
|
{
|
|
if(destruct)
|
|
destruct->destroy(dataPointer());
|
|
else
|
|
{
|
|
for(dd=(gdd*)dataPointer();dd;)
|
|
{
|
|
temp=dd;
|
|
dd=dd->next();
|
|
temp->unreference();
|
|
}
|
|
freeBounds();
|
|
}
|
|
}
|
|
else if(isAtomic())
|
|
{
|
|
if(destruct) destruct->destroy(dataPointer());
|
|
if(bounds) freeBounds();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// this destroys any scalar string data that may be present
|
|
//
|
|
this->setPrimType (aitEnumInvalid);
|
|
}
|
|
this->setApplType (0);
|
|
memset ( & this->data, '\0', sizeof ( this->data ) );
|
|
}
|
|
|
|
// this routine is private so we dont need to initialize
|
|
// string data when changing to a scalar, but we do need
|
|
// to be careful about how it is called
|
|
void gdd::freeBounds(void)
|
|
{
|
|
if(bounds)
|
|
{
|
|
switch(dim)
|
|
{
|
|
case 0:
|
|
fprintf ( stderr, "gdd: freeing bounds, bounds exist, but gdd is scalar?\n" );
|
|
break;
|
|
case 1: { gddBounds1D* d1=(gddBounds1D*)bounds; delete d1; } break;
|
|
case 2: { gddBounds2D* d2=(gddBounds2D*)bounds; delete d2; } break;
|
|
case 3: { gddBounds3D* d3=(gddBounds3D*)bounds; delete d3; } break;
|
|
default: delete [] bounds; break;
|
|
}
|
|
bounds=NULL;
|
|
}
|
|
dim=0;
|
|
}
|
|
|
|
void gdd::setDimension(int d, const gddBounds* bnds)
|
|
{
|
|
if ( dim != 0 ) {
|
|
if ( isFlat() || isManaged() ) {
|
|
throw std::logic_error (
|
|
"sorry: cant change the bounds on an atomic, managed or flat gdd" );
|
|
}
|
|
}
|
|
if(dim!=d)
|
|
{
|
|
if ( dim == 0 ) {
|
|
// run destructors for scalar string data
|
|
if ( primitiveType() == aitEnumFixedString )
|
|
{
|
|
// aitString type could have destructors
|
|
if ( destruct ) {
|
|
destruct->destroy(dataPointer());
|
|
destruct = 0;
|
|
}
|
|
else
|
|
if (data.FString) delete data.FString;
|
|
}
|
|
else if ( primitiveType() == aitEnumString )
|
|
{
|
|
// aitString type could have destructors
|
|
if ( destruct ) {
|
|
destruct->destroy(dataAddress());
|
|
destruct = 0;
|
|
}
|
|
else
|
|
{
|
|
aitString* s = (aitString*)dataAddress();
|
|
s->clear();
|
|
}
|
|
}
|
|
// changing from scalar to vector so set the
|
|
// vector pointer to nill
|
|
memset ( & this->data, '\0', sizeof ( this->data ) );
|
|
}
|
|
else {
|
|
this->freeBounds();
|
|
}
|
|
dim=(aitUint8)d;
|
|
switch(dim)
|
|
{
|
|
case 0: bounds=0; break;
|
|
case 1: bounds=(gddBounds*)new gddBounds1D; bounds->set(0,0); break;
|
|
case 2: bounds=(gddBounds*)new gddBounds2D; break;
|
|
case 3: bounds=(gddBounds*)new gddBounds3D; break;
|
|
default: bounds=(gddBounds*)new gddBounds[dim]; break;
|
|
}
|
|
if ( dim == 0 ) {
|
|
if ( destruct ) {
|
|
destruct->destroy(dataAddress());
|
|
destruct = 0;
|
|
}
|
|
// run constructers for scalar string data types
|
|
if ( primitiveType() == aitEnumString ) {
|
|
aitString* str=(aitString*)dataAddress();
|
|
str->init();
|
|
}
|
|
else if ( primitiveType() ==aitEnumFixedString ) {
|
|
this->data.FString = new aitFixedString;
|
|
memset (this->data.FString, '\0', sizeof(aitFixedString));
|
|
}
|
|
else {
|
|
memset ( & this->data, '\0', sizeof ( this->data ) );
|
|
}
|
|
}
|
|
}
|
|
if ( bnds )
|
|
{
|
|
for(int i=0;i<dim;i++)
|
|
bounds[i]=bnds[i];
|
|
}
|
|
}
|
|
|
|
gddStatus gdd::registerDestructor(gddDestructor* dest)
|
|
{
|
|
// this is funky, will not register a destructor if one is present
|
|
if(destruct)
|
|
{
|
|
gddAutoPrint("gdd::registerDestructor()",gddErrorAlreadyDefined);
|
|
return gddErrorAlreadyDefined;
|
|
}
|
|
else
|
|
return replaceDestructor(dest);
|
|
}
|
|
|
|
gddStatus gdd::replaceDestructor(gddDestructor* dest)
|
|
{
|
|
destruct=dest;
|
|
destruct->reference();
|
|
|
|
if(isContainer()||isFlat())
|
|
markManaged();
|
|
|
|
return 0;
|
|
}
|
|
|
|
gddStatus gdd::genCopy(aitEnum t, const void* d, aitDataFormat f)
|
|
{
|
|
gddStatus rc=0;
|
|
|
|
if(isScalar())
|
|
set(t,d,f);
|
|
else if(isAtomic())
|
|
{
|
|
if(!dataPointer())
|
|
{
|
|
if ( primitiveType()==aitEnumString ) {
|
|
size_t nElem = describedDataSizeElements ();
|
|
aitString * pStrVec = new aitString [ nElem ];
|
|
if ( ! pStrVec ) {
|
|
gddAutoPrint("gdd::genCopy()",gddErrorNewFailed);
|
|
rc = gddErrorNewFailed;
|
|
}
|
|
else {
|
|
destruct = new gddAitStringDestructor;
|
|
if ( destruct ) {
|
|
destruct->reference();
|
|
setData ( pStrVec );
|
|
}
|
|
else {
|
|
delete [] pStrVec;
|
|
gddAutoPrint("gdd::genCopy()",gddErrorNewFailed);
|
|
rc = gddErrorNewFailed;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
size_t sz=describedDataSizeBytes();
|
|
aitUint8 * buf = new aitUint8[sz];
|
|
if ( buf == NULL ) {
|
|
gddAutoPrint("gdd::genCopy()",gddErrorNewFailed);
|
|
rc=gddErrorNewFailed;
|
|
}
|
|
else
|
|
{
|
|
destruct=new gddAitUint8Destructor;
|
|
if (destruct==NULL) {
|
|
gddAutoPrint("gdd::genCopy()",gddErrorNewFailed);
|
|
rc=gddErrorNewFailed;
|
|
delete [] buf;
|
|
}
|
|
else {
|
|
setData(buf);
|
|
destruct->reference();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(rc==0)
|
|
{
|
|
if(f==aitLocalDataFormat)
|
|
aitConvert(primitiveType(),dataPointer(),t,d,
|
|
getDataSizeElements());
|
|
else
|
|
aitConvertFromNet(primitiveType(),dataPointer(),t,d,
|
|
getDataSizeElements());
|
|
|
|
markLocalDataFormat();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gddAutoPrint("gdd::genCopy()",gddErrorTypeMismatch);
|
|
rc=gddErrorTypeMismatch;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
gddStatus gdd::changeType(int app,aitEnum prim)
|
|
{
|
|
gddStatus rc=0;
|
|
|
|
// this should only be allowed for setting the type if it is
|
|
// undefined or if the data is a scalar
|
|
|
|
if(isScalar() || primitiveType()==aitEnumInvalid)
|
|
{
|
|
setApplType(app);
|
|
setPrimType(prim);
|
|
}
|
|
else
|
|
{
|
|
gddAutoPrint("gdd::changeType()",gddErrorTypeMismatch);
|
|
rc=gddErrorTypeMismatch;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
gddStatus gdd::setBound(unsigned index_dim, aitIndex first, aitIndex count)
|
|
{
|
|
gddStatus rc=0;
|
|
if(index_dim<dimension())
|
|
bounds[index_dim].set(first,count);
|
|
else
|
|
{
|
|
gddAutoPrint("gdd::setBound()",gddErrorOutOfBounds);
|
|
rc=gddErrorOutOfBounds;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
gddStatus gdd::getBound(unsigned index_dim, aitIndex& first, aitIndex& count) const
|
|
{
|
|
gddStatus rc=0;
|
|
if(index_dim<dimension())
|
|
bounds[index_dim].get(first,count);
|
|
else
|
|
{
|
|
gddAutoPrint("gdd::getBound()",gddErrorOutOfBounds);
|
|
rc=gddErrorOutOfBounds;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
// should the copy functions in gdd use the flatten technique?
|
|
gddStatus gdd::copyStuff(const gdd* dd,int ctype)
|
|
{
|
|
gddStatus rc=0;
|
|
gddContainer* cdd;
|
|
gdd *pdd,*ndd;
|
|
|
|
// blow me out quickly here
|
|
if(isFlat()||isManaged())
|
|
{
|
|
gddAutoPrint("gdd::copyStuff()",gddErrorNotAllowed);
|
|
return gddErrorNotAllowed;
|
|
}
|
|
|
|
clear();
|
|
|
|
setApplType(dd->appl_type);
|
|
setPrimType(aitEnumContainer);
|
|
setStatSevr(dd->getStat(),dd->getSevr());
|
|
|
|
if(dd->isContainer())
|
|
{
|
|
cdd=(gddContainer*)dd;
|
|
gddCursor cur=cdd->getCursor();
|
|
for(ndd=cur.first();ndd;ndd=cur.next())
|
|
{
|
|
pdd=new gdd(ndd->applicationType(),
|
|
ndd->primitiveType(),ndd->dimension());
|
|
pdd->setNext((gdd*)dataPointer());
|
|
setData(pdd);
|
|
bounds->setSize(bounds->size()+1);
|
|
pdd->copyStuff(ndd,ctype);
|
|
}
|
|
}
|
|
else if(dd->isScalar()) {
|
|
if (dd->primitiveType()==aitEnumString) {
|
|
aitString* pStrDest =(aitString*)&data;
|
|
aitString* pStrSrc =(aitString*)&dd->data;
|
|
*pStrDest = *pStrSrc;
|
|
}
|
|
else if (dd->primitiveType()==aitEnumFixedString) {
|
|
aitFixedString* pStrDest =(aitFixedString*)data.Pointer;
|
|
aitFixedString* pStrSrc =(aitFixedString*)dd->data.Pointer;
|
|
memcpy (pStrDest, pStrSrc, sizeof(aitFixedString));
|
|
}
|
|
else {
|
|
data=dd->data;
|
|
}
|
|
}
|
|
else // atomic
|
|
{
|
|
const gddBounds* bnds = dd->getBounds();
|
|
for(unsigned i=0;i<dd->dimension();i++) bounds[i]=bnds[i];
|
|
|
|
switch(ctype)
|
|
{
|
|
case 1: // copy()
|
|
if ( primitiveType()==aitEnumString ) {
|
|
size_t nElem = dd->describedDataSizeElements ();
|
|
aitString * pStrVec = new aitString [ nElem ];
|
|
if ( ! pStrVec ) {
|
|
gddAutoPrint("gdd::copyStuff()",gddErrorNewFailed);
|
|
rc=gddErrorNewFailed;
|
|
}
|
|
else {
|
|
destruct = new gddAitStringDestructor;
|
|
if ( destruct ) {
|
|
const aitString * pSrc =
|
|
static_cast <const aitString *> ( dd->dataPointer() );
|
|
for ( unsigned j=0; j < nElem; j++ ) {
|
|
pStrVec[j] = pSrc[j];
|
|
}
|
|
destruct->reference();
|
|
setData ( pStrVec );
|
|
}
|
|
else {
|
|
delete [] pStrVec;
|
|
gddAutoPrint("gdd::copyStuff()",gddErrorNewFailed);
|
|
rc=gddErrorNewFailed;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
size_t a_size = dd->getDataSizeBytes();
|
|
aitUint8* array = new aitUint8[a_size];
|
|
if ( array ) {
|
|
destruct=new gddAitUint8Destructor;
|
|
if (destruct!=NULL) {
|
|
destruct->reference();
|
|
memcpy(array,dd->dataPointer(),a_size);
|
|
setData(array);
|
|
}
|
|
else {
|
|
delete [] array;
|
|
gddAutoPrint("gdd::copyStuff()",gddErrorNewFailed);
|
|
rc=gddErrorNewFailed;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gddAutoPrint("gdd::copyStuff()",gddErrorNewFailed);
|
|
rc=gddErrorNewFailed;
|
|
}
|
|
}
|
|
break;
|
|
case 2: // Dup()
|
|
data=dd->getData(); // copy the data reference
|
|
destruct=dd->destruct;
|
|
if(destruct) destruct->reference();
|
|
break;
|
|
case 0: // copyInfo()
|
|
default: break;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
size_t gdd::getDataSizeBytes(void) const
|
|
{
|
|
size_t sz=0;
|
|
const gdd* pdd;
|
|
aitString* str;
|
|
|
|
if(isContainer())
|
|
{
|
|
const gddContainer* cdd=(const gddContainer*)this;
|
|
constGddCursor cur=cdd->getCursor();
|
|
for(pdd=cur.first();pdd;pdd=cur.next())
|
|
sz+=pdd->getTotalSizeBytes();
|
|
}
|
|
else
|
|
{
|
|
if(aitValid(primitiveType()))
|
|
{
|
|
if(primitiveType()==aitEnumString)
|
|
{
|
|
if(dimension()) str=(aitString*)dataPointer();
|
|
else str=(aitString*)dataAddress();
|
|
sz+=(size_t)(aitString::totalLength(str,
|
|
getDataSizeElements()));
|
|
}
|
|
else
|
|
sz+=(size_t)(getDataSizeElements())*aitSize[primitiveType()];
|
|
}
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
size_t gdd::describedDataSizeBytes(void) const
|
|
{
|
|
size_t sz=0;
|
|
|
|
// does not work well for aitString - only reports the aitString info
|
|
|
|
if(!isContainer())
|
|
sz+=(size_t)(describedDataSizeElements())*aitSize[primitiveType()];
|
|
|
|
return sz;
|
|
}
|
|
|
|
size_t gdd::getTotalSizeBytes(void) const
|
|
{
|
|
size_t sz;
|
|
unsigned long tsize;
|
|
const gdd* pdd;
|
|
|
|
// add up size of bounds + size of this DD
|
|
sz=sizeof(gdd)+(sizeof(gddBounds)*dimension());
|
|
|
|
// special case the aitString/aitFixedString here - sucks bad
|
|
if(isScalar())
|
|
{
|
|
if(primitiveType()==aitEnumString)
|
|
{
|
|
aitString* str=(aitString*)dataAddress();
|
|
sz+=str->length()+1; // include the NULL
|
|
}
|
|
else if(primitiveType()==aitEnumFixedString)
|
|
sz+=sizeof(aitFixedString);
|
|
}
|
|
else if(isAtomic())
|
|
{
|
|
if(aitValid(primitiveType()))
|
|
{
|
|
if(primitiveType()==aitEnumString)
|
|
{
|
|
// special case the aitString here
|
|
tsize=(size_t)(aitString::totalLength((aitString*)dataPointer(),
|
|
getDataSizeElements()));
|
|
}
|
|
else
|
|
tsize=(size_t)(getDataSizeElements())*aitSize[primitiveType()];
|
|
|
|
sz+=(size_t)align8(tsize); // include alignment
|
|
}
|
|
}
|
|
else if(isContainer())
|
|
{
|
|
const gddContainer* cdd=(const gddContainer*)this;
|
|
constGddCursor cur=cdd->getCursor();
|
|
for(pdd=cur.first();pdd;pdd=cur.next())
|
|
sz+=pdd->getTotalSizeBytes();
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
aitUint32 gdd::getDataSizeElements(void) const
|
|
{
|
|
unsigned long total=1u;
|
|
unsigned i;
|
|
|
|
if(dimension()>0u && dataPointer())
|
|
{
|
|
for(i=0u;i<dimension();i++)
|
|
total*=bounds[i].size();
|
|
}
|
|
|
|
return total;
|
|
}
|
|
|
|
aitUint32 gdd::describedDataSizeElements(void) const
|
|
{
|
|
unsigned long total=0;
|
|
unsigned i;
|
|
|
|
if(dimension()==0)
|
|
total=1;
|
|
else
|
|
for(i=0;i<dimension();i++) total+=bounds[i].size();
|
|
|
|
return total;
|
|
}
|
|
|
|
size_t gdd::flattenWithOffsets(void* buf, size_t size, aitIndex* total_dd)
|
|
{
|
|
gdd* flat_dd;
|
|
size_t sz;
|
|
|
|
sz = flattenWithAddress(buf,size,total_dd);
|
|
flat_dd=(gdd*)buf;
|
|
if(sz>0) flat_dd->convertAddressToOffsets();
|
|
return sz;
|
|
}
|
|
|
|
// IMPORTANT NOTE:
|
|
// Currently the user cannot register an empty container as a prototype.
|
|
// The destructor will not be installed to clean up the container when
|
|
// it is freed.
|
|
|
|
// This is an important function
|
|
// Data should be flattened as follows:
|
|
// 1) all the GDDs, seen as an array an GDDs
|
|
// 2) all the bounds info for all the GDDs
|
|
// 3) all the data for all GDDs
|
|
//
|
|
// In addition, the user should be able to flatten GDDs without the data
|
|
// and flatten portions or all the data without flattening GDDs
|
|
|
|
size_t gdd::flattenWithAddress(void* buf, size_t size, aitIndex* total_dd)
|
|
{
|
|
gdd* pdd = (gdd*)buf;
|
|
size_t pos,sz,spos;
|
|
aitUint32 i;
|
|
gddBounds* bnds;
|
|
|
|
// copy this gdd (first one) to get things started
|
|
// this is done in two passes - one to copy DDs, one for bounds/data
|
|
// need to be able to check if the DD has been flattened already
|
|
|
|
if((sz=getTotalSizeBytes())>size) return 0;
|
|
pdd[0]=*this;
|
|
pdd[0].destruct=NULL;
|
|
pdd[0].flags=0;
|
|
pos=1;
|
|
|
|
// not enough to just copy the gdd info if the primitive type is
|
|
// aitString or aitFixedString (even if scalar gdd)
|
|
// must special case the strings - that really sucks
|
|
|
|
if(isScalar())
|
|
{
|
|
// here is special case for the string types
|
|
if(primitiveType()==aitEnumFixedString)
|
|
{
|
|
if(data.FString)
|
|
memcpy((char*)&pdd[pos],data.FString,sizeof(aitFixedString));
|
|
|
|
pdd[0].data.FString=(aitFixedString*)&pdd[pos];
|
|
}
|
|
else if(primitiveType()==aitEnumString)
|
|
{
|
|
aitString* str=(aitString*)pdd[0].dataAddress();
|
|
if(str->string())
|
|
{
|
|
memcpy((char*)&pdd[pos],str->string(),str->length()+1);
|
|
str->installBuf((char*)&pdd[pos],str->length(),str->length()+1);
|
|
}
|
|
else
|
|
str->init();
|
|
}
|
|
}
|
|
else if(isContainer())
|
|
{
|
|
// need to check for bounds in the container and flatten them
|
|
if(dataPointer())
|
|
{
|
|
// process all the container's DDs
|
|
spos=pos;
|
|
pos+=flattenDDs((gddContainer*)this,&pdd[pos],
|
|
size-(pos*sizeof(gdd)));
|
|
|
|
// copy all the data from the entire container into the buffer
|
|
flattenData(&pdd[0],pos,&pdd[pos],size-(pos*sizeof(gdd)));
|
|
|
|
pdd[0].markFlat();
|
|
pdd[0].setData(&pdd[spos]);
|
|
}
|
|
else
|
|
sz=0; // failure should occur - cannot flatten an empty container
|
|
}
|
|
else if(isAtomic())
|
|
{
|
|
// Just copy the data from this DD into the buffer, copy bounds
|
|
if(bounds)
|
|
{
|
|
pdd[0].markFlat();
|
|
bnds=(gddBounds*)(&pdd[pos]);
|
|
for(i=0;i<dimension();i++) bnds[i]=bounds[i];
|
|
pdd[0].bounds=bnds;
|
|
if(dataPointer())
|
|
{
|
|
if(primitiveType()==aitEnumString)
|
|
{
|
|
// not very good way to do it, size info bad
|
|
aitString* str = (aitString*)dataPointer();
|
|
aitString::compact(str,getDataSizeElements(),&bnds[i],size);
|
|
}
|
|
else
|
|
memcpy(&bnds[i],dataPointer(),getDataSizeBytes());
|
|
|
|
pdd[0].setData(&bnds[i]);
|
|
}
|
|
else
|
|
sz=0; // should return a failure
|
|
}
|
|
else
|
|
sz=0; // should return failure
|
|
}
|
|
if(total_dd) *total_dd=pos;
|
|
return sz;
|
|
}
|
|
|
|
gddStatus gdd::flattenData(gdd* dd, int tot_dds, void* buf,size_t size)
|
|
{
|
|
int i;
|
|
unsigned j;
|
|
size_t sz;
|
|
gddBounds* bnds;
|
|
aitUint8* ptr = (aitUint8*)buf;
|
|
|
|
// This functions needs to be divided into two sections
|
|
// 1) copy ALL the bounds out
|
|
// 2) copy ALL the data out
|
|
|
|
for(i=0;i<tot_dds;i++)
|
|
{
|
|
if(dd[i].isContainer())
|
|
{
|
|
// don't mark flat if container - 1D bounds must be present
|
|
if(dd[i].bounds)
|
|
{
|
|
bnds=(gddBounds*)(ptr);
|
|
for(j=0;j<dd[i].dimension();j++) bnds[j]=dd[i].bounds[j];
|
|
dd[i].bounds=bnds;
|
|
ptr+=j*sizeof(gddBounds);
|
|
}
|
|
else
|
|
{
|
|
// this is an error condition!
|
|
dd[i].bounds=NULL;
|
|
}
|
|
}
|
|
else if(dd[i].isAtomic())
|
|
{
|
|
if(dd[i].bounds)
|
|
{
|
|
// copy the bounds
|
|
// need to mark flat if bounds are present in an atomic type
|
|
dd[i].markFlat();
|
|
bnds=(gddBounds*)(ptr);
|
|
for(j=0;j<dd[i].dimension();j++) bnds[j]=dd[i].bounds[j];
|
|
dd[i].bounds=bnds;
|
|
ptr+=j*sizeof(gddBounds);
|
|
|
|
// copy the data
|
|
if(dd[i].dataPointer())
|
|
{
|
|
if(dd[i].primitiveType()==aitEnumString)
|
|
{
|
|
// not very good way to do it, size info bad
|
|
aitString* str = (aitString*)dd[i].dataPointer();
|
|
sz=aitString::compact(str,
|
|
dd[i].getDataSizeElements(),ptr,size);
|
|
}
|
|
else
|
|
{
|
|
// need to copy data here, align to size of double
|
|
sz=dd[i].getDataSizeBytes();
|
|
memcpy(ptr,dd[i].dataPointer(),sz);
|
|
}
|
|
dd[i].setData(ptr);
|
|
ptr+=align8(sz); // do alignment
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// bounds not required
|
|
dd[i].bounds=NULL;
|
|
}
|
|
}
|
|
else if(dd[i].isScalar())
|
|
{
|
|
// here is special case for String types
|
|
if(dd[i].primitiveType()==aitEnumString)
|
|
{
|
|
aitString* str=(aitString*)dd[i].dataAddress();
|
|
if(str->string())
|
|
{
|
|
memcpy(ptr,str->string(),str->length()+1);
|
|
str->installBuf((char *)ptr, str->length(), str->length()+1);
|
|
ptr+=str->length()+1;
|
|
}
|
|
else
|
|
str->init();
|
|
}
|
|
else if(dd[i].primitiveType()==aitEnumFixedString)
|
|
{
|
|
if(dd[i].data.FString)
|
|
memcpy(ptr,dd[i].data.FString,sizeof(aitFixedString));
|
|
dd[i].data.FString=(aitFixedString*)ptr;
|
|
ptr+=sizeof(aitFixedString);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int gdd::flattenDDs(gddContainer* dd, void* buf, size_t size)
|
|
{
|
|
gdd* ptr=(gdd*)buf;
|
|
int i,tot,pos,spos;
|
|
gdd *pdd;
|
|
gddCursor cur;
|
|
|
|
cur=dd->getCursor();
|
|
|
|
// make first pass to copy all the container's DDs into the buffer
|
|
for(tot=0,pdd=cur.first();pdd;pdd=pdd->next(),tot++)
|
|
{
|
|
ptr[tot]=*pdd;
|
|
ptr[tot].destruct=NULL;
|
|
ptr[tot].setNext(&ptr[tot+1]);
|
|
ptr[tot].noReferencing();
|
|
}
|
|
ptr[tot-1].setNext(NULL);
|
|
|
|
// make second pass to copy all child containers into buffer
|
|
for(pos=tot,i=0;i<tot;i++)
|
|
{
|
|
if(ptr[i].isContainer())
|
|
{
|
|
if(ptr[i].dataPointer())
|
|
{
|
|
spos=pos;
|
|
pos+=flattenDDs((gddContainer*)&ptr[i],&ptr[pos],
|
|
size-(pos*sizeof(gdd)));
|
|
ptr[i].markFlat();
|
|
ptr[i].setData(&ptr[spos]);
|
|
}
|
|
else
|
|
{
|
|
ptr[i].setData(NULL);
|
|
ptr[i].destruct=new gddContainerCleaner(&ptr[i]);
|
|
ptr[i].destruct->reference();
|
|
}
|
|
}
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
gddStatus gdd::convertOffsetsToAddress(void)
|
|
{
|
|
aitUint8* pdd = (aitUint8*)this;
|
|
unsigned long bnds = (unsigned long)(bounds);
|
|
unsigned long dp = (unsigned long)(dataPointer());
|
|
gdd* tdd;
|
|
gddContainer* cdd;
|
|
gddCursor cur;
|
|
aitString* str;
|
|
aitIndex i;
|
|
const char* cstr;
|
|
|
|
if(isContainer())
|
|
{
|
|
// change bounds and data first
|
|
bounds=(gddBounds*)(pdd+bnds);
|
|
setData(pdd+dp);
|
|
cdd=(gddContainer*)this;
|
|
cur=cdd->getCursor();
|
|
|
|
for(tdd=cur.first();tdd;tdd=cur.next())
|
|
{
|
|
if(tdd->next()) tdd->setNext((gdd*)(pdd+(unsigned long)tdd->next()));
|
|
tdd->convertOffsetsToAddress();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(isAtomic())
|
|
{
|
|
bounds=(gddBounds*)(pdd+bnds);
|
|
setData(pdd+dp);
|
|
if(primitiveType()==aitEnumString)
|
|
{
|
|
// force all the strings in the array to offsets
|
|
str=(aitString*)dataPointer();
|
|
for(i=0;i<getDataSizeElements();i++)
|
|
{
|
|
if(str[i].string())
|
|
{
|
|
cstr=str[i].string();
|
|
str[i].installBuf((char *)(pdd+(unsigned long)cstr),
|
|
str[i].length(), str[i].length()+1);
|
|
}
|
|
else
|
|
str[i].init();
|
|
}
|
|
}
|
|
}
|
|
else if(isScalar())
|
|
{
|
|
if(primitiveType()==aitEnumFixedString)
|
|
{
|
|
if(data.FString) setData(pdd+dp);
|
|
}
|
|
else if(primitiveType()==aitEnumString)
|
|
{
|
|
str=(aitString*)dataAddress();
|
|
if(str->string())
|
|
{
|
|
cstr=str->string();
|
|
str->installBuf((char *)(pdd+(unsigned long)cstr),
|
|
str->length(), str->length()+1u);
|
|
}
|
|
else
|
|
str->init();
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
gddStatus gdd::convertAddressToOffsets(void)
|
|
{
|
|
aitUint8* pdd = (aitUint8*)this;
|
|
aitUint8* bnds = (aitUint8*)(bounds);
|
|
aitUint8* dp = (aitUint8*)(dataPointer());
|
|
gddContainer* tdd;
|
|
gddCursor cur;
|
|
gdd *cdd,*ddd;
|
|
aitString* str;
|
|
aitIndex i;
|
|
const char* cstr;
|
|
|
|
// does not ensure that all the members of a container are flat!
|
|
if(!isFlat())
|
|
{
|
|
gddAutoPrint("gdd::convertAddressToOffsets()",gddErrorNotAllowed);
|
|
return gddErrorNotAllowed;
|
|
}
|
|
|
|
if(isContainer())
|
|
{
|
|
tdd=(gddContainer*)this;
|
|
cur=tdd->getCursor();
|
|
|
|
for(cdd=cur.first();cdd;)
|
|
{
|
|
ddd=cdd;
|
|
cdd=cur.next();
|
|
ddd->convertAddressToOffsets();
|
|
if(cdd) ddd->setNext((gdd*)((aitUint8*)(ddd->next())-pdd));
|
|
}
|
|
|
|
// bounds and data of container to offsets
|
|
setData((gdd*)(dp-pdd));
|
|
bounds=(gddBounds*)(bnds-pdd);
|
|
}
|
|
else
|
|
{
|
|
if(isAtomic())
|
|
{
|
|
if(primitiveType()==aitEnumString)
|
|
{
|
|
// force all the strings in the array to offsets
|
|
str=(aitString*)dataPointer();
|
|
for(i=0;i<getDataSizeElements();i++)
|
|
{
|
|
cstr=str[i].string();
|
|
if(cstr) str[i].installBuf((char *)(cstr-(const char*)pdd),
|
|
str[i].length(), str[i].length()+1u);
|
|
else str[i].init();
|
|
}
|
|
}
|
|
// bounds and data of atomic to offsets
|
|
setData((gdd*)(dp-pdd));
|
|
bounds=(gddBounds*)(bnds-pdd);
|
|
}
|
|
else if(isScalar())
|
|
{
|
|
// handle the special string scalar cases
|
|
if(primitiveType()==aitEnumFixedString)
|
|
{
|
|
if(data.FString) setData((gdd*)(dp-pdd));
|
|
}
|
|
else if(primitiveType()==aitEnumString)
|
|
{
|
|
str=(aitString*)dataAddress();
|
|
cstr=str->string();
|
|
if(cstr) str->installBuf((char *)(cstr-(const char*)pdd),
|
|
str->length(), str->length()+1u);
|
|
else str->init();
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void gdd::destroyData(void)
|
|
{
|
|
if (isScalar())
|
|
{
|
|
// this destroys the string types
|
|
this->setPrimType (aitEnumInvalid);
|
|
memset ( & this->data, '\0', sizeof ( this->data ) );
|
|
}
|
|
else {
|
|
if(destruct)
|
|
{
|
|
if(isContainer())
|
|
destruct->destroy(this);
|
|
else
|
|
destruct->destroy(dataPointer());
|
|
|
|
destruct=NULL;
|
|
}
|
|
freeBounds();
|
|
this->prim_type = aitEnumInvalid;
|
|
memset ( & this->data, '\0', sizeof ( this->data ) );
|
|
}
|
|
}
|
|
|
|
gddStatus gdd::clearData(void)
|
|
{
|
|
gddStatus rc=0;
|
|
|
|
if(isContainer()||isManaged()||isFlat())
|
|
{
|
|
gddAutoPrint("gdd::clearData()",gddErrorNotAllowed);
|
|
rc=gddErrorNotAllowed;
|
|
}
|
|
else if ( this->isScalar () ) {
|
|
// clear scaler types
|
|
if ( this->primitiveType() == aitEnumString ) {
|
|
aitString * str=(aitString*)dataAddress();
|
|
str->clear();
|
|
}
|
|
else if ( this->primitiveType() == aitEnumFixedString ) {
|
|
memset ( this->data.FString, '\0', sizeof ( this->data.FString ) );
|
|
}
|
|
else {
|
|
memset ( & this->data, '\0', sizeof ( this->data ) );
|
|
}
|
|
}
|
|
else {
|
|
if(destruct)
|
|
{
|
|
destruct->destroy(dataPointer());
|
|
destruct=NULL;
|
|
}
|
|
setDimension ( 0, 0 );
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
gddStatus gdd::clear(void)
|
|
{
|
|
if(isFlat()||isManaged())
|
|
{
|
|
gddAutoPrint("gdd::clear()",gddErrorNotAllowed);
|
|
return gddErrorNotAllowed;
|
|
}
|
|
|
|
if(isAtomic())
|
|
{
|
|
destroyData();
|
|
}
|
|
else if(isContainer())
|
|
{
|
|
gddContainer* cdd = (gddContainer*)this;
|
|
gddCursor cur = cdd->getCursor();
|
|
gdd *dd,*tdd;
|
|
|
|
for(dd=cur.first();dd;)
|
|
{
|
|
tdd=dd;
|
|
dd=cur.next();
|
|
if(tdd->unreference()<0) delete tdd;
|
|
}
|
|
freeBounds();
|
|
}
|
|
|
|
//
|
|
// this code clears out aitString and
|
|
// aitFixedString scalars (the doc says
|
|
// that every field is set to invalid)
|
|
//
|
|
changeType(0,aitEnumInvalid);
|
|
memset ( & this->data, '\0', sizeof ( this->data ) );
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Curently gives no indication of failure, which is bad.
|
|
// Obviously managed or flattened DDs cannot be redone.
|
|
// However, a DD that is within a managed or flattened container can
|
|
// use this to describe data - how's that for obscure
|
|
// This is required if the "value" is to be allowed within a container
|
|
// The "value" could be scalar or an array of unknown size. The same is
|
|
// true of the enum strings and "units" attribute.
|
|
|
|
gddStatus gdd::reset(aitEnum prim, int dimen, aitIndex* cnt)
|
|
{
|
|
int i;
|
|
gddStatus rc;
|
|
|
|
if((rc=clear())==0)
|
|
{
|
|
setPrimType(prim);
|
|
setDimension(dimen);
|
|
for(i=0;i<dimen;i++)
|
|
setBound(i,0,cnt[i]);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
void gdd::get(aitString& d) const
|
|
{
|
|
if(primitiveType()==aitEnumString)
|
|
{
|
|
aitString* s=(aitString*)dataAddress();
|
|
d=*s;
|
|
}
|
|
else
|
|
get(aitEnumString,&d);
|
|
}
|
|
void gdd::get(aitFixedString& d) const
|
|
{
|
|
if(primitiveType()==aitEnumFixedString){
|
|
strncpy(d.fixed_string,data.FString->fixed_string,
|
|
sizeof(d));
|
|
d.fixed_string[sizeof(d)-1u] = '\0';
|
|
}
|
|
else
|
|
get(aitEnumFixedString,&d);
|
|
}
|
|
|
|
void gdd::getConvert(aitString& d) const
|
|
{
|
|
get(aitEnumString,&d);
|
|
}
|
|
|
|
void gdd::getConvert(aitFixedString& d) const
|
|
{
|
|
get(aitEnumFixedString,d.fixed_string);
|
|
}
|
|
|
|
gddStatus gdd::put(const aitString& d)
|
|
{
|
|
gddStatus rc=0;
|
|
if(isScalar())
|
|
{
|
|
//
|
|
// destroy existing fixed string if it exists
|
|
// and construct new aitString object
|
|
//
|
|
setPrimType(aitEnumString);
|
|
aitString* s=(aitString*)dataAddress();
|
|
*s=d;
|
|
}
|
|
else
|
|
{
|
|
gddAutoPrint("gdd::put(aitString&)",gddErrorNotAllowed);
|
|
rc=gddErrorNotAllowed;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
gddStatus gdd::put(const aitFixedString& d)
|
|
{
|
|
gddStatus rc=0;
|
|
|
|
if(isScalar())
|
|
{
|
|
this->setPrimType(aitEnumFixedString);
|
|
|
|
if (data.FString!=NULL)
|
|
memcpy (data.FString->fixed_string, d.fixed_string, sizeof(d.fixed_string));
|
|
}
|
|
else
|
|
{
|
|
gddAutoPrint("gdd::put(aitString&)",gddErrorNotAllowed);
|
|
rc=gddErrorNotAllowed;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
void gdd::putConvert(const aitString& d)
|
|
{
|
|
set(aitEnumString,&d);
|
|
}
|
|
|
|
void gdd::putConvert(const aitFixedString& d)
|
|
{
|
|
set(aitEnumFixedString,(void*)d.fixed_string);
|
|
}
|
|
|
|
// copy each of the strings into this DDs storage area
|
|
gddStatus gdd::put(const aitString* const d)
|
|
{
|
|
return genCopy(aitEnumString,d);
|
|
}
|
|
|
|
// copy each of the strings into this DDs storage area
|
|
gddStatus gdd::put(const aitFixedString* const d)
|
|
{
|
|
gddStatus rc=0;
|
|
|
|
if(isAtomic())
|
|
if(dataPointer())
|
|
aitConvert(primitiveType(),dataPointer(),aitEnumFixedString,d,
|
|
getDataSizeElements());
|
|
else
|
|
genCopy(aitEnumFixedString,d);
|
|
else
|
|
{
|
|
gddAutoPrint("gdd::put(const aitFixedString*const)",gddErrorNotAllowed);
|
|
rc=gddErrorTypeMismatch;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
gddStatus gdd::putRef(const gdd*)
|
|
{
|
|
gddAutoPrint("gdd::putRef(const gdd*) - NOT IMPLEMENTED",
|
|
gddErrorNotSupported);
|
|
return gddErrorNotSupported;
|
|
}
|
|
|
|
gddStatus gdd::put ( const gdd * dd )
|
|
{
|
|
if ( this->isScalar() && dd->isScalar() )
|
|
{
|
|
// this is the simple case - just make this scalar look like the other
|
|
this->set(dd->primitiveType(),dd->dataVoid());
|
|
}
|
|
else if ( isContainer() || dd->isContainer() )
|
|
{
|
|
gddAutoPrint("gdd::put(const gdd*)",gddErrorNotSupported);
|
|
return gddErrorNotSupported;
|
|
}
|
|
else if ( this->dimension() > 1 || dd->dimension() > 1 )
|
|
{
|
|
// sorry, no support currently for multidimensional arrays
|
|
return gddErrorOutOfBounds;
|
|
}
|
|
else if ( this->isScalar() ) // dd must be atomic if this is true
|
|
{
|
|
this->set ( dd->primitiveType(), dd->dataPointer() );
|
|
}
|
|
// at this point this GDD must be atomic
|
|
// and the src gdd is either atomic or scalar
|
|
else {
|
|
// this must be single dimensional atomic at this point
|
|
|
|
// dd can be scaler or single dimensional atomic at this point
|
|
// so fetch the bounds carefully
|
|
aitUint32 srcFirst;
|
|
aitUint32 srcElemCount;
|
|
if ( dd->isScalar() ) {
|
|
srcFirst = 0;
|
|
srcElemCount = 1;
|
|
}
|
|
else {
|
|
srcFirst = dd->getBounds()->first();
|
|
srcElemCount = dd->getBounds()->size();
|
|
}
|
|
|
|
// clip to lower limit of source
|
|
aitUint32 srcCopyFirst;
|
|
if ( this->getBounds()->first () > srcFirst ) {
|
|
srcCopyFirst = this->getBounds()->first();
|
|
}
|
|
else {
|
|
srcCopyFirst = srcFirst;
|
|
}
|
|
|
|
// clip to upper limit of source
|
|
aitUint32 srcCopySize;
|
|
const aitUint32 unusedSrcBelow = srcCopyFirst - srcFirst;
|
|
if ( srcElemCount <= unusedSrcBelow ) {
|
|
return gddErrorOutOfBounds;
|
|
}
|
|
|
|
aitUint32 srcAvailSize = srcElemCount - unusedSrcBelow;
|
|
if ( srcAvailSize > this->getBounds()->size() ) {
|
|
srcCopySize = this->getBounds()->size();
|
|
}
|
|
else {
|
|
srcCopySize = srcAvailSize;
|
|
}
|
|
|
|
if ( dataVoid() == NULL )
|
|
{
|
|
if (primitiveType()==aitEnumInvalid) {
|
|
setPrimType (dd->primitiveType());
|
|
}
|
|
if ( primitiveType()==aitEnumString ) {
|
|
aitString * pStrVec = new aitString [ srcCopySize ];
|
|
if( ! pStrVec ) {
|
|
return gddErrorNewFailed;
|
|
}
|
|
destruct = new gddAitStringDestructor;
|
|
if ( destruct ) {
|
|
destruct->reference();
|
|
setData ( pStrVec );
|
|
}
|
|
else {
|
|
delete [] pStrVec;
|
|
gddAutoPrint("gdd::copyData(const gdd*)",gddErrorNewFailed);
|
|
return gddErrorNewFailed;
|
|
}
|
|
}
|
|
else {
|
|
size_t sz = srcCopySize * aitSize[primitiveType()];
|
|
|
|
// allocate a data buffer for the user
|
|
aitUint8 * arr = new aitUint8[sz];
|
|
if( ! arr ) {
|
|
return gddErrorNewFailed;
|
|
}
|
|
destruct=new gddAitUint8Destructor;
|
|
if (destruct!=NULL) {
|
|
destruct->reference();
|
|
setData(arr);
|
|
}
|
|
else {
|
|
delete [] arr;
|
|
gddAutoPrint("gdd::copyData(const gdd*)",gddErrorNewFailed);
|
|
return gddErrorNewFailed;
|
|
}
|
|
}
|
|
|
|
// the rule is that if storage is not preallocated then its ok
|
|
// for the dest bounds to shrink to match the original dest
|
|
// bounds intersection with the source data bounds
|
|
for ( unsigned i = 0; i < this->dimension(); i++ ) {
|
|
if ( i == 0 ) {
|
|
this->setBound ( i, srcCopyFirst, srcCopySize );
|
|
}
|
|
else {
|
|
this->setBound ( i, 0, 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
aitUint8* pDst = (aitUint8*) this->dataPointer();
|
|
assert ( srcCopyFirst >= this->getBounds()->first() );
|
|
const aitUint32 unusedDstLow = srcCopyFirst - this->getBounds()->first();
|
|
if ( unusedDstLow > 0 ) {
|
|
//
|
|
// zero portions that dont match
|
|
// (should eventually throw an exception ?)
|
|
//
|
|
aitUint32 byteCount = aitSize[primitiveType()] * unusedDstLow;
|
|
memset (pDst, '\0', byteCount);
|
|
pDst += byteCount;
|
|
}
|
|
|
|
aitUint8* pSrc = (aitUint8*) dd->dataVoid();
|
|
pSrc += aitSize[dd->primitiveType()] * unusedSrcBelow;
|
|
int gddStatus = aitConvert (this->primitiveType(), pDst,
|
|
dd->primitiveType(), pSrc, srcCopySize);
|
|
if ( gddStatus < 0 ) {
|
|
return gddErrorTypeMismatch;
|
|
}
|
|
|
|
assert ( this->getBounds()->size() >= srcCopySize + unusedDstLow );
|
|
const aitUint32 unusedDstHigh = this->getBounds()->size() - ( srcCopySize + unusedDstLow );
|
|
if ( unusedDstHigh > 0 ) {
|
|
pDst += aitSize[primitiveType()] * srcCopySize;
|
|
//
|
|
// zero portions that dont match
|
|
// (should eventually throw an exception ?)
|
|
//
|
|
aitUint32 byteCount = aitSize[primitiveType()] * unusedDstHigh;
|
|
memset (pDst, '\0', byteCount);
|
|
}
|
|
}
|
|
|
|
setStatSevr(dd->getStat(),dd->getSevr());
|
|
aitTimeStamp ts;
|
|
dd->getTimeStamp(&ts);
|
|
setTimeStamp(&ts);
|
|
|
|
return 0; // success
|
|
}
|
|
|
|
size_t gdd::outHeader(void* buf,aitUint32 bufsize) const
|
|
{
|
|
// simple encoding for now.. will change later
|
|
// this is the SLOW, simple version
|
|
|
|
aitUint8* b = (aitUint8*)buf;
|
|
aitUint8* app = (aitUint8*)&appl_type;
|
|
aitUint8* stat = (aitUint8*)&status;
|
|
aitUint8* ts_sec = (aitUint8*)&time_stamp.tv_sec;
|
|
aitUint8* ts_nsec = (aitUint8*)&time_stamp.tv_nsec;
|
|
size_t i,j,sz;
|
|
aitIndex ff,ss;
|
|
aitUint8 *f,*s;
|
|
|
|
// verify that header will fit into buffer first
|
|
sz=4+sizeof(status)+sizeof(time_stamp)+sizeof(appl_type)+
|
|
sizeof(prim_type)+sizeof(dim)+(dim*sizeof(gddBounds));
|
|
|
|
if(sz>bufsize) return 0; // blow out here!
|
|
|
|
*(b++)='H'; *(b++)='E'; *(b++)='A'; *(b++)='D';
|
|
|
|
// how's this for putrid
|
|
*(b++)=dim;
|
|
*(b++)=prim_type;
|
|
|
|
if(aitLocalNetworkDataFormatSame)
|
|
{
|
|
*(b++)=app[0]; *(b++)=app[1];
|
|
for(i=0;i<sizeof(status);i++) *(b++)=stat[i];
|
|
for(i=0;i<sizeof(time_stamp.tv_sec);i++) *(b++)=ts_sec[i];
|
|
for(i=0;i<sizeof(time_stamp.tv_nsec);i++) *(b++)=ts_nsec[i];
|
|
}
|
|
else
|
|
{
|
|
*(b++)=app[1]; *(b++)=app[0];
|
|
i=sizeof(status)-1u; do { *(b++)=stat[i]; } while(i-->0u);
|
|
i=sizeof(time_stamp.tv_sec)-1u; do { *(b++)=ts_sec[i]; } while(i-->0u);
|
|
i=sizeof(time_stamp.tv_nsec)-1u; do { *(b++)=ts_nsec[i]; } while(i-->0u);
|
|
}
|
|
|
|
// put out the bounds info
|
|
for(j=0;j<dim;j++)
|
|
{
|
|
ff=bounds[j].first(); f=(aitUint8*)&ff;
|
|
ss=bounds[j].size(); s=(aitUint8*)&ss;
|
|
if(aitLocalNetworkDataFormatSame)
|
|
{
|
|
for(i=0;i<sizeof(aitIndex);i++) *(b++)=s[i];
|
|
for(i=0;i<sizeof(aitIndex);i++) *(b++)=f[i];
|
|
}
|
|
else
|
|
{
|
|
i=sizeof(aitIndex)-1u; do { *(b++)=s[i]; } while(i-->0u);
|
|
i=sizeof(aitIndex)-1u; do { *(b++)=f[i]; } while(i-->0u);
|
|
}
|
|
}
|
|
return sz;
|
|
}
|
|
size_t gdd::outData(void* buf,aitUint32 bufsize, aitEnum e, aitDataFormat f) const
|
|
{
|
|
// put data into user's buffer in the format that the user wants (e/f).
|
|
// if e is invalid, then use whatever format this gdd describes.
|
|
|
|
aitUint32 sz = getDataSizeElements();
|
|
aitUint32 len = getDataSizeBytes();
|
|
aitEnum type=(e==aitEnumInvalid)?primitiveType():e;
|
|
|
|
if(len>bufsize) return 0; // blow out early
|
|
|
|
if(sz>0)
|
|
{
|
|
if(f==aitLocalDataFormat)
|
|
aitConvert(type,buf,primitiveType(),dataVoid(),sz);
|
|
else
|
|
aitConvertToNet(type,buf,primitiveType(),dataVoid(),sz);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
size_t gdd::out(void* buf,aitUint32 bufsize,aitDataFormat f) const
|
|
{
|
|
size_t index = outHeader(buf,bufsize);
|
|
size_t rc;
|
|
|
|
if(index>0)
|
|
rc=outData(((char*)buf)+index,bufsize-index,aitEnumInvalid,f)+index;
|
|
else
|
|
rc=0;
|
|
|
|
return rc;
|
|
}
|
|
|
|
size_t gdd::inHeader(void* buf)
|
|
{
|
|
// simple encoding for now.. will change later
|
|
// this is the SLOW, simple version
|
|
|
|
aitUint16 inapp;
|
|
aitUint8 inprim;
|
|
aitUint8 indim;
|
|
|
|
aitUint8* b = (aitUint8*)buf;
|
|
aitUint8* b1 = b;
|
|
aitUint8* app = (aitUint8*)&inapp;
|
|
aitUint8* stat = (aitUint8*)&status;
|
|
aitUint8* ts_sec = (aitUint8*)&time_stamp.tv_sec;
|
|
aitUint8* ts_nsec = (aitUint8*)&time_stamp.tv_nsec;
|
|
size_t i,j;
|
|
aitIndex ff,ss;
|
|
aitUint8 *f,*s;
|
|
|
|
if(strncmp((char*)b,"HEAD",4)!=0) return 0;
|
|
b+=4;
|
|
|
|
indim=*(b++);
|
|
inprim=*(b++);
|
|
|
|
if(aitLocalNetworkDataFormatSame)
|
|
{
|
|
app[0]=*(b++); app[1]=*(b++);
|
|
init(inapp,(aitEnum)inprim,indim);
|
|
for(i=0u;i<sizeof(status);i++) stat[i]=*(b++);
|
|
for(i=0u;i<sizeof(time_stamp.tv_sec);i++) ts_sec[i]=*(b++);
|
|
for(i=0u;i<sizeof(time_stamp.tv_nsec);i++) ts_nsec[i]=*(b++);
|
|
}
|
|
else
|
|
{
|
|
app[1]=*(b++); app[0]=*(b++);
|
|
init(inapp,(aitEnum)inprim,indim);
|
|
i=sizeof(status)-1u; do { stat[i]=*(b++); } while(i-->0u);
|
|
i=sizeof(time_stamp.tv_sec)-1u; do { ts_sec[i]=*(b++); } while(i-->0u);
|
|
i=sizeof(time_stamp.tv_nsec)-1u; do { ts_nsec[i]=*(b++); } while(i-->0u);
|
|
}
|
|
|
|
// read in the bounds info
|
|
f=(aitUint8*)&ff;
|
|
s=(aitUint8*)&ss;
|
|
|
|
for(j=0u;j<dim;j++)
|
|
{
|
|
if(aitLocalNetworkDataFormatSame)
|
|
{
|
|
for(i=0;i<sizeof(aitIndex);i++) s[i]=*(b++);
|
|
for(i=0;i<sizeof(aitIndex);i++) f[i]=*(b++);
|
|
}
|
|
else
|
|
{
|
|
i=sizeof(aitIndex)-1u; do { s[i]=*(b++); } while(i-->0u);
|
|
i=sizeof(aitIndex)-1u; do { f[i]=*(b++); } while(i-->0u);
|
|
}
|
|
bounds[j].setFirst(ff);
|
|
bounds[j].setSize(ss);
|
|
}
|
|
return (size_t)(b-b1);
|
|
}
|
|
size_t gdd::inData(void* buf,aitUint32 tot, aitEnum e, aitDataFormat f)
|
|
{
|
|
size_t rc;
|
|
|
|
// Get data from a buffer and put it into this gdd. Lots of rules here.
|
|
// 1) tot is the total number of elements to copy from buf to this gdd.
|
|
// * if tot is zero, then use the element count described in the gdd.
|
|
// * if tot is not zero, then set the gdd up as a 1 dimensional array
|
|
// with tot elements in it.
|
|
// 2) e is the primitive data type of the incoming data.
|
|
// * if e is aitEnumInvalid, then use the gdd primitive type.
|
|
// * if e is valid and gdd primitive type is invalid, set the gdd
|
|
// primitive type to e.
|
|
// * if e is valid and so is this gdd primitive type, then convert the
|
|
// incoming data from type e to gdd primitive type.
|
|
|
|
// Bad error condition, don't do anything.
|
|
if(e==aitEnumInvalid && primitiveType()==aitEnumInvalid)
|
|
return 0;
|
|
|
|
aitIndex sz=tot;
|
|
aitEnum src_type=(e==aitEnumInvalid)?primitiveType():e;
|
|
aitEnum dest_type=(primitiveType()==aitEnumInvalid)?e:primitiveType();
|
|
|
|
// I'm not sure if this is the best way to do this.
|
|
if(sz>0)
|
|
reset(dest_type,dimension(),&sz);
|
|
|
|
if(genCopy(src_type,buf,f)==0)
|
|
rc=getDataSizeBytes();
|
|
else
|
|
rc=0;
|
|
|
|
return rc;
|
|
}
|
|
size_t gdd::in(void* buf, aitDataFormat f)
|
|
{
|
|
size_t index = inHeader(buf);
|
|
size_t rc;
|
|
|
|
if(index>0)
|
|
rc=inData(((char*)buf)+index,0,aitEnumInvalid,f)+index;
|
|
else
|
|
rc=0;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
//
|
|
// rewrote this to properly construct/destruct
|
|
// scalar string types when the prim type changes
|
|
// joh 05-22-98
|
|
//
|
|
//
|
|
void gdd::setPrimType (aitEnum t)
|
|
{
|
|
//
|
|
// NOOP if there is no change
|
|
//
|
|
if ( this->prim_type == t ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// I (joh) assume that something needs to be done when
|
|
// the primative type of a container changes. For now I
|
|
// assuming that the gdd should be cleared.
|
|
//
|
|
if(isContainer()) {
|
|
this->clear();
|
|
}
|
|
|
|
//
|
|
// run constructors/destructors for string data
|
|
// if it is scalar
|
|
//
|
|
if (isScalar())
|
|
{
|
|
//
|
|
// run destructors for existing string data
|
|
//
|
|
if(primitiveType()==aitEnumFixedString)
|
|
{
|
|
// aitString type could have destructors
|
|
if ( destruct ) {
|
|
destruct->destroy(dataPointer());
|
|
destruct = 0;
|
|
}
|
|
else
|
|
if (data.FString) delete data.FString;
|
|
}
|
|
else if(primitiveType()==aitEnumString)
|
|
{
|
|
// aitString type could have destructors
|
|
if ( destruct ) {
|
|
destruct->destroy(dataAddress());
|
|
destruct = 0;
|
|
}
|
|
else
|
|
{
|
|
aitString* s = (aitString*)dataAddress();
|
|
s->clear();
|
|
}
|
|
}
|
|
|
|
//
|
|
// run constructors for new string data types
|
|
//
|
|
if (t==aitEnumString) {
|
|
aitString* str=(aitString*)dataAddress();
|
|
str->init();
|
|
}
|
|
else if (t==aitEnumFixedString) {
|
|
this->data.FString = new aitFixedString;
|
|
memset ( this->data.FString, '\0', sizeof(aitFixedString) );
|
|
}
|
|
else {
|
|
memset ( & this->data, '\0', sizeof(this->data) );
|
|
}
|
|
}
|
|
|
|
//
|
|
// I (joh) assume that Jim intended that
|
|
// calling of the destructors for arrays of string
|
|
// data when the primitive type changes is handled
|
|
// by the application. Not sure - nothing was done
|
|
// by Jim to take care of this as far as I can tell.
|
|
//
|
|
else if(isAtomic())
|
|
{
|
|
if ( dataPointer() && destruct ) {
|
|
destruct->destroy(dataPointer());
|
|
destruct=NULL;
|
|
}
|
|
memset (&this->data, '\0', sizeof(this->data));
|
|
}
|
|
|
|
this->prim_type = t;
|
|
}
|
|
|
|
//
|
|
// gdd::indexDD()
|
|
//
|
|
// modified by JOH 4-23-99 so that the correct method
|
|
// is used if the container gdd is not organized
|
|
// as an array of GDDs in memory (i.e. its not flat)
|
|
//
|
|
const gdd* gdd::indexDD (aitIndex index) const
|
|
{
|
|
aitIndex i;
|
|
unsigned nElem;
|
|
|
|
if (index==0u) {
|
|
return this;
|
|
}
|
|
|
|
//
|
|
// otherwise this had better be a container
|
|
// we are indexing
|
|
//
|
|
assert (this->prim_type==aitEnumContainer);
|
|
|
|
//
|
|
// catch out of bounds index
|
|
//
|
|
nElem = getDataSizeElements();
|
|
assert (index<=nElem);
|
|
|
|
//
|
|
// if the container GDD is "flat"
|
|
//
|
|
if (this->isFlat()) {
|
|
return this + index;
|
|
}
|
|
|
|
//
|
|
// otherwise linear search for it
|
|
//
|
|
gdd* dd = (gdd*) dataPointer();
|
|
i = nElem;
|
|
while (i>index) {
|
|
dd=(gdd*)dd->next();
|
|
i--;
|
|
}
|
|
return dd;
|
|
}
|
|
|
|
//
|
|
// gddAitUint8Destructor::run()
|
|
//
|
|
// special gddDestructor guarantees same form of new and delete
|
|
//
|
|
void gddAitUint8Destructor::run (void *pUntyped)
|
|
{
|
|
aitUint8 *pui8 = (aitUint8 *) pUntyped;
|
|
delete [] pui8;
|
|
}
|
|
|
|
//
|
|
// gddAitStringDestructor::run()
|
|
//
|
|
// special gddDestructor guarantees same form of new and delete
|
|
//
|
|
void gddAitStringDestructor::run (void *pUntyped)
|
|
{
|
|
aitString *pStr = (aitString *) pUntyped;
|
|
delete [] pStr;
|
|
}
|
|
|