/*************************************************************************\ * 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: anj@aps.anl.gov-20101005192737-disfz3vs0f3fiixd // #include #include #include #include #include #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;iremove(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;iprim_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;ireference(); 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_dimappl_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;idimension();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 ( 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;i0) 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;istring()) { 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;ireference(); } } } 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;istring()) { 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;istring(); 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;ifixed_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;i0u); 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;j0u); 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;i0u); 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;j0u); 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; }