1 
2 /*
3 * NIST STEP Core Class Library
4 * clstepcore/sdaiApplication_instance.cc
5 * July, 1997
6 * K. C. Morris
7 * David Sauder
8 
9 * Development of this software was funded by the United States Government,
10 * and is not subject to copyright.
11 */
12 
13 #include <map>
14 #include <sdai.h>
15 #include <instmgr.h>
16 #include <STEPcomplex.h>
17 #include <STEPattribute.h>
18 #include <read_func.h> //for ReadTokenSeparator, used when comments are inside entities
19 
20 #include "sdaiApplication_instance.h"
21 #include "superInvAttrIter.h"
22 
23 SDAI_Application_instance NilSTEPentity;
24 
25 /**************************************************************//**
26 ** \file sdaiApplication_instance.cc  Functions for manipulating entities
27 **
28 **  KNOWN BUGs:  the SDAI_Application_instance is not aware of the STEPfile;
29 **    therefore it can not read comments which may be embedded in the instance.
30 **    The following are known problems:
31 **    -- does not handle comments embedded in an instance ==> bombs
32 **    -- ignores embedded entities ==> does not bomb
33 **    -- error reporting does not include line number information
34 */
35 
SDAI_Application_instance()36 SDAI_Application_instance::SDAI_Application_instance()
37     :  _cur( 0 ),
38        eDesc( NULL ),
39        _complex( false ),
40        STEPfile_id( 0 ),
41        p21Comment( std::string( "" ) ),
42        headMiEntity( 0 ),
43        nextMiEntity( 0 ) {
44 }
45 
SDAI_Application_instance(int fileid,int complex)46 SDAI_Application_instance::SDAI_Application_instance( int fileid, int complex )
47     :  _cur( 0 ),
48        eDesc( NULL ),
49        _complex( complex ),
50        STEPfile_id( fileid ),
51        p21Comment( std::string( "" ) ),
52        headMiEntity( 0 ),
53        nextMiEntity( 0 ) {
54 }
55 
~SDAI_Application_instance()56 SDAI_Application_instance::~SDAI_Application_instance() {
57     STEPattribute * attr;
58 
59     ResetAttributes();
60     do {
61         attr = NextAttribute();
62         if( attr ) {
63             attr->refCount --;
64             if( attr->refCount <= 0 ) {
65                 delete attr;
66             }
67         }
68     } while( attr );
69 
70 
71     if( MultipleInheritance() ) {
72         delete nextMiEntity;
73     }
74 }
75 
76 
77 /// initialize inverse attrs
78 /// eDesc->InitIAttrs() must have been called previously
79 /// call once per instance (*not* once per class)
InitIAttrs()80 void SDAI_Application_instance::InitIAttrs() {
81     assert( eDesc && "eDesc must be set; please report this bug." );
82     InverseAItr iai( &( eDesc->InverseAttr() ) );
83     const Inverse_attribute * ia;
84     iAstruct s;
85     memset( &s, 0, sizeof s );
86     while( 0 != ( ia = iai.NextInverse_attribute() ) ) {
87         iAMap.insert( iAMap_t::value_type( ia, s ) );
88     }
89     superInvAttrIter siai( eDesc );
90     while( !siai.empty() ) {
91         ia = siai.next();
92         assert( ia && "Null inverse attr!" );
93         iAMap.insert( iAMap_t::value_type( ia, s ) );
94     }
95 }
96 
Replicate()97 SDAI_Application_instance * SDAI_Application_instance::Replicate() {
98     char errStr[BUFSIZ];
99     if( IsComplex() ) {
100         cerr << "STEPcomplex::Replicate() should be called:  " << __FILE__
101              <<  __LINE__ << "\n" << _POC_ "\n";
102         sprintf( errStr,
103                  "SDAI_Application_instance::Replicate(): %s - entity #%d.\n",
104                  "Programming ERROR - STEPcomplex::Replicate() should be called",
105                  STEPfile_id );
106         _error.AppendToDetailMsg( errStr );
107         _error.AppendToUserMsg( errStr );
108         _error.GreaterSeverity( SEVERITY_BUG );
109         return S_ENTITY_NULL;
110     } else {
111         if( !eDesc ) {
112             return S_ENTITY_NULL;
113         }
114 
115         SDAI_Application_instance * seNew = eDesc->NewSTEPentity();
116         seNew -> CopyAs( this );
117         return seNew;
118     }
119 }
120 
AddP21Comment(const char * s,bool replace)121 void SDAI_Application_instance::AddP21Comment( const char * s, bool replace ) {
122     if( replace ) {
123         p21Comment.clear();
124     }
125     if( s ) {
126         p21Comment += s;
127     }
128 }
129 
AddP21Comment(const std::string & s,bool replace)130 void SDAI_Application_instance::AddP21Comment( const std::string & s, bool replace ) {
131     if( replace ) {
132         p21Comment.clear();
133     }
134     p21Comment += s;
135 }
136 
PrependP21Comment(const std::string & s)137 void SDAI_Application_instance::PrependP21Comment( const std::string & s ) {
138     p21Comment.insert( 0, s );
139 }
140 
STEPwrite_reference(ostream & out)141 void SDAI_Application_instance::STEPwrite_reference( ostream & out ) {
142     out << "#" << STEPfile_id;
143 }
144 
STEPwrite_reference(std::string & buf)145 const char * SDAI_Application_instance::STEPwrite_reference( std::string & buf ) {
146     char tmp[64];
147     sprintf( tmp, "#%d", STEPfile_id );
148     buf = tmp;
149     return const_cast<char *>( buf.c_str() );
150 }
151 
AppendMultInstance(SDAI_Application_instance * se)152 void SDAI_Application_instance::AppendMultInstance( SDAI_Application_instance * se ) {
153     if( nextMiEntity == 0 ) {
154         nextMiEntity = se;
155     } else {
156         SDAI_Application_instance * link = nextMiEntity;
157         SDAI_Application_instance * linkTrailing = 0;
158         while( link ) {
159             linkTrailing = link;
160             link = link->nextMiEntity;
161         }
162         linkTrailing->nextMiEntity = se;
163     }
164 }
165 
166 // BUG implement this -- FIXME function is never used
167 
GetMiEntity(char * entName)168 SDAI_Application_instance * SDAI_Application_instance::GetMiEntity( char * entName ) {
169     std::string s1, s2;
170 
171     const EntityDescLinkNode * edln = 0;
172     const EntityDescriptor * ed = eDesc;
173 
174     // compare up the *leftmost* parent path
175     while( ed ) {
176         if( !strcmp( StrToLower( ed->Name(), s1 ), StrToLower( entName, s2 ) ) ) {
177             return this;    // return this parent path
178         }
179         edln = ( EntityDescLinkNode * )( ed->Supertypes().GetHead() );
180         if( edln ) {
181             ed = edln->EntityDesc();
182         } else {
183             ed = 0;
184         }
185     }
186     // search alternate parent path since didn't find it in this one.
187     if( nextMiEntity ) {
188         return nextMiEntity->GetMiEntity( entName );
189     }
190     return 0;
191 }
192 
193 
194 /**
195  * Returns a STEPattribute or NULL
196  * \param nm The name to search for.
197  * \param entity If not null, check that the attribute comes from this entity. When MakeDerived is called from generated code, this is used to ensure that the correct attr is marked as derived. Issue #232
198  */
GetSTEPattribute(const char * nm,const char * entity)199 STEPattribute * SDAI_Application_instance::GetSTEPattribute( const char * nm, const char * entity ) {
200     if( !nm ) {
201         return 0;
202     }
203     STEPattribute * a = 0;
204 
205     ResetAttributes();
206     // keep going until no more attributes, or attribute is found
207     while( ( a = NextAttribute() ) ) {
208         if( 0 == strcmp( nm, a ->Name() ) &&
209             //if entity isn't null, check for a match. NOTE: should we use IsA(), CanBe(), or Name()?
210             ( entity ? ( 0 != a->aDesc->Owner().IsA( entity ) ) : true ) ) {
211             break;
212         }
213     }
214 
215     return a;
216 }
217 
MakeRedefined(STEPattribute * redefiningAttr,const char * nm)218 STEPattribute * SDAI_Application_instance::MakeRedefined( STEPattribute * redefiningAttr, const char * nm ) {
219     // find the attribute being redefined
220     STEPattribute * a = GetSTEPattribute( nm );
221 
222     // assign its pointer to the redefining attribute
223     if( a ) {
224         a->RedefiningAttr( redefiningAttr );
225     }
226     return a;
227 }
228 
229 /**
230  * Returns a STEPattribute or NULL. If found, marks as derived.
231  * \param nm The name to search for.
232  * \param entity If not null, check that the attribute comes from this entity. When called from generated code, this is used to ensure that the correct attr is marked as derived. Issue #232
233  */
MakeDerived(const char * nm,const char * entity)234 STEPattribute * SDAI_Application_instance::MakeDerived( const char * nm, const char * entity ) {
235     STEPattribute * a = GetSTEPattribute( nm, entity );
236     if( a ) {
237         a ->Derive();
238     }
239     return a;
240 }
241 
CopyAs(SDAI_Application_instance * other)242 void SDAI_Application_instance::CopyAs( SDAI_Application_instance * other ) {
243     int numAttrs = AttributeCount();
244     ResetAttributes();
245     other -> ResetAttributes();
246 
247     STEPattribute * this_attr = 0;
248     STEPattribute * other_attr = 0;
249     while( ( this_attr = NextAttribute() ) && numAttrs ) {
250         other_attr = other -> NextAttribute();
251         this_attr -> ShallowCopy( other_attr );
252         numAttrs--;
253     }
254 }
255 
256 
EntityName(const char * schnm) const257 const char * SDAI_Application_instance::EntityName( const char * schnm ) const {
258     if( !eDesc ) {
259         return NULL;
260     }
261     return eDesc->Name( schnm );
262 }
263 
264 /**
265  * Checks if a given SDAI_Application_instance is the same
266  * type as this one
267  */
IsA(const EntityDescriptor * ed) const268 const EntityDescriptor * SDAI_Application_instance::IsA( const EntityDescriptor * ed ) const {
269     if( !eDesc ) {
270         return NULL;
271     }
272     return ( eDesc->IsA( ed ) );
273 }
274 
275 /**
276  * Checks the validity of the current attribute values for the entity
277  */
ValidLevel(ErrorDescriptor * error,InstMgrBase * im,int clearError)278 Severity SDAI_Application_instance::ValidLevel( ErrorDescriptor * error, InstMgrBase * im,
279         int clearError ) {
280     ErrorDescriptor err;
281     if( clearError ) {
282         ClearError();
283     }
284     int n = attributes.list_length();
285     for( int i = 0 ; i < n; i++ ) {
286         if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) )
287             error->GreaterSeverity( attributes[i].ValidLevel(
288                                         attributes[i].asStr().c_str(), &err, im, 0 ) );
289     }
290     return error->severity();
291 }
292 
293 /**
294  * clears all attr's errors
295  */
ClearAttrError()296 void SDAI_Application_instance::ClearAttrError() {
297     int n = attributes.list_length();
298     for( int i = 0 ; i < n; i++ ) {
299         attributes[i].Error().ClearErrorMsg();
300     }
301 }
302 
303 /**
304  * clears entity's error and optionally all attr's errors
305  */
ClearError(int clearAttrs)306 void SDAI_Application_instance::ClearError( int clearAttrs ) {
307     _error.ClearErrorMsg();
308     if( clearAttrs ) {
309         ClearAttrError();
310     }
311 }
312 
313 /**************************************************************//**
314 ** \param out -- stream to write to
315 ** \details
316 ** Side Effects:  writes out the SCOPE section for an entity
317 ** Status:  stub FIXME
318 *******************************************************************/
beginSTEPwrite(ostream & out)319 void SDAI_Application_instance::beginSTEPwrite( ostream & out ) {
320     out << "begin STEPwrite ... \n" ;
321     out.flush();
322 
323     int n = attributes.list_length();
324     for( int i = 0 ; i < n; i++ ) {
325         if( attributes[i].Type() == ENTITY_TYPE
326                 && *( attributes[i].ptr.c ) != S_ENTITY_NULL ) {
327             ( *( attributes[i].ptr.c ) ) -> STEPwrite();
328         }
329     }
330 }
331 
332 /**************************************************************//**
333 ** \param out -- stream to write to
334 ** \details
335 ** Side Effects:  writes out the data associated with an instance
336 **                  in STEP format
337 ** Problems:  does not print out the SCOPE section of an entity
338 **
339 *******************************************************************/
STEPwrite(ostream & out,const char * currSch,int writeComments)340 void SDAI_Application_instance::STEPwrite( ostream & out, const char * currSch,
341         int writeComments ) {
342     std::string tmp;
343     if( writeComments && !p21Comment.empty() ) {
344         out << p21Comment;
345     }
346     out << "#" << STEPfile_id << "=" << StrToUpper( EntityName( currSch ), tmp )
347         << "(";
348     int n = attributes.list_length();
349 
350     for( int i = 0 ; i < n; i++ ) {
351         if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) ) {
352             if( i > 0 ) {
353                 out << ",";
354             }
355             ( attributes[i] ).STEPwrite( out, currSch );
356         }
357     }
358     out << ");\n";
359 }
360 
endSTEPwrite(ostream & out)361 void SDAI_Application_instance::endSTEPwrite( ostream & out ) {
362     out << "end STEPwrite ... \n" ;
363     out.flush();
364 }
365 
WriteValuePairs(ostream & out,const char * currSch,int writeComments,int mixedCase)366 void SDAI_Application_instance::WriteValuePairs( ostream & out,
367         const char * currSch,
368         int writeComments, int mixedCase ) {
369     std::string s, tmp, tmp2;
370 
371     if( writeComments && !p21Comment.empty() ) {
372         out << p21Comment;
373     }
374 
375     if( eDesc ) {
376         if( mixedCase ) {
377             out << "#" << STEPfile_id << " "
378                 << eDesc->QualifiedName( s ) << endl;
379         } else {
380             out << "#" << STEPfile_id << " "
381                 << StrToUpper( eDesc->QualifiedName( s ), tmp ) << endl;
382         }
383     }
384 
385     int n = attributes.list_length();
386 
387     for( int i = 0 ; i < n; i++ ) {
388         if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) ) {
389             if( mixedCase ) {
390                 out << "\t"
391                     << attributes[i].aDesc->Owner().Name( s.c_str() )
392                     << "." << attributes[i].aDesc->Name() << " ";
393             } else {
394                 out << "\t"
395                     << StrToUpper( attributes[i].aDesc->Owner().Name( s.c_str() ), tmp )
396                     << "." << StrToUpper( attributes[i].aDesc->Name(), tmp2 ) << " ";
397             }
398             ( attributes[i] ).STEPwrite( out, currSch );
399             out << endl;
400         }
401     }
402     out << endl;
403 }
404 
405 
406 /******************************************************************
407  ** Procedure:  STEPwrite
408  ** Problems:  does not print out the SCOPE section of an entity
409  ******************************************************************/
STEPwrite(std::string & buf,const char * currSch)410 const char * SDAI_Application_instance::STEPwrite( std::string & buf, const char * currSch ) {
411     buf.clear();
412 
413     char instanceInfo[BUFSIZ];
414 
415     std::string tmp;
416     sprintf( instanceInfo, "#%d=%s(", STEPfile_id, StrToUpper( EntityName( currSch ), tmp ) );
417     buf.append( instanceInfo );
418 
419     int n = attributes.list_length();
420 
421     for( int i = 0 ; i < n; i++ ) {
422         if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) ) {
423             if( i > 0 ) {
424                 buf.append( "," );
425             }
426             tmp = attributes[i].asStr( currSch ) ;
427             buf.append( tmp );
428         }
429     }
430     buf.append( ");" );
431     return const_cast<char *>( buf.c_str() );
432 }
433 
PrependEntityErrMsg()434 void SDAI_Application_instance::PrependEntityErrMsg() {
435     char errStr[BUFSIZ];
436     errStr[0] = '\0';
437 
438     if( _error.severity() == SEVERITY_NULL ) {
439         //  if there is not an error already
440         sprintf( errStr, "\nERROR:  ENTITY #%d %s\n", GetFileId(),
441                  EntityName() );
442         _error.PrependToDetailMsg( errStr );
443     }
444 }
445 
446 /**************************************************************//**
447  ** \param c --  character which caused error
448  ** \param i --  index of attribute which caused error
449  ** \param in -- (used in STEPcomplex) input stream for recovery
450  ** Reports the error found, reads until it finds the end of an
451  ** instance. i.e. a close quote followed by a semicolon optionally
452  ** having whitespace between them.
453  ******************************************************************/
STEPread_error(char c,int i,istream & in,const char * schnm)454 void SDAI_Application_instance::STEPread_error( char c, int i, istream & in, const char * schnm ) {
455     (void) in;
456     char errStr[BUFSIZ];
457     errStr[0] = '\0';
458 
459     if( _error.severity() == SEVERITY_NULL ) {
460         //  if there is not an error already
461         sprintf( errStr, "\nERROR:  ENTITY #%d %s\n", GetFileId(),
462                  EntityName() );
463         _error.PrependToDetailMsg( errStr );
464     }
465 
466     if( ( i >= 0 ) && ( i < attributes.list_length() ) ) { // i is an attribute
467         Error().GreaterSeverity( SEVERITY_WARNING );
468         sprintf( errStr, "  invalid data before type \'%s\'\n",
469                  attributes[i].TypeName() );
470         _error.AppendToDetailMsg( errStr );
471     } else {
472         Error().GreaterSeverity( SEVERITY_INPUT_ERROR );
473         _error.AppendToDetailMsg( "  No more attributes were expected.\n" );
474     }
475 
476     std::string tmp;
477     STEPwrite( tmp, schnm ); // STEPwrite writes to a static buffer inside function
478     _error.AppendToDetailMsg( "  The invalid instance to this point looks like :\n" );
479     _error.AppendToDetailMsg( tmp );
480     _error.AppendToDetailMsg( "\nUnexpected character: " );
481     _error.AppendToDetailMsg( c );
482     _error.AppendToDetailMsg( '\n' );
483 
484     sprintf( errStr, "\nfinished reading #%d\n", STEPfile_id );
485     _error.AppendToDetailMsg( errStr );
486     return;
487 }
488 
489 /**************************************************************//**
490  ** \returns Severity, error information
491  **          SEVERITY_NULL - no errors
492  **          SEVERITY_USERMSG - checked as much as possible, could still
493  **            be error - e.g. entity didn't match base entity type.
494  **          SEVERITY_INCOMPLETE - data is missing and required.
495  **          SEVERITY_WARNING - errors, but can recover
496  **            <= SEVERITY_INPUT_ERROR - fatal error, can't recover
497  ** \details  reads the values for an entity from an input stream
498  **            in STEP file format starting at the open paren and
499  **            ending with the semi-colon
500  ** Side Effects:  gobbles up input stream
501  ** Status:
502  ******************************************************************/
STEPread(int id,int idIncr,InstMgrBase * instance_set,istream & in,const char * currSch,bool useTechCor,bool strict)503 Severity SDAI_Application_instance::STEPread( int id,  int idIncr,
504         InstMgrBase * instance_set, istream & in,
505         const char * currSch, bool useTechCor, bool strict ) {
506     STEPfile_id = id;
507     char c = '\0';
508     char errStr[BUFSIZ];
509     errStr[0] = '\0';
510     Severity severe;
511     int i = 0;
512 
513     ClearError( 1 );
514 
515     in >> ws;
516     in >> c; // read the open paren
517     if( c != '(' ) {
518         PrependEntityErrMsg();
519         _error.AppendToDetailMsg(
520             "  Missing initial open paren... Trying to recover.\n" );
521         in.putback( c ); // assume you can recover by reading 1st attr value
522     }
523     ReadTokenSeparator( in, &p21Comment );
524 
525     int n = attributes.list_length();
526     if( n == 0 ) { // no attributes
527         in >> c; // look for the close paren
528         if( c == ')' ) {
529             return _error.severity();
530         }
531     }
532 
533     for( i = 0 ; i < n; i++ ) {
534         ReadTokenSeparator( in, &p21Comment );
535         if( attributes[i].aDesc->AttrType() == AttrType_Redefining ) {
536             in >> ws;
537             c = in.peek();
538             if( !useTechCor ) { // i.e. use pre-technical corrigendum encoding
539                 in >> c; // read what should be the '*'
540                 in >> ws;
541                 if( c == '*' ) {
542                     in >> c; // read the delimiter i.e. ',' or ')'
543                 } else {
544                     severe = SEVERITY_INCOMPLETE;
545                     PrependEntityErrMsg(); // adds entity info if necessary
546 
547                     // set the severity for this entity
548                     _error.GreaterSeverity( severe );
549                     sprintf( errStr, "  %s :  ", attributes[i].Name() );
550                     _error.AppendToDetailMsg( errStr ); // add attr name
551                     _error.AppendToDetailMsg(
552                         "Since using pre-technical corrigendum... missing asterisk for redefined attr.\n" );
553                     _error.AppendToUserMsg(
554                         "Since using pre-technical corrigendum... missing asterisk for redefined attr. " );
555                 }
556             } else { // using technical corrigendum
557                 // should be nothing to do except loop again unless...
558                 // if at end need to have read the closing paren.
559                 if( c == ')' ) { // assume you are at the end so read last char
560                     in >> c;
561                 }
562                 cout << "Entity #" << STEPfile_id
563                      << " skipping redefined attribute "
564                      << attributes[i].aDesc->Name() << endl << endl << flush;
565             }
566             // increment counter to read following attr since these attrs
567             // aren't written or read => there won't be a delimiter either
568         } else {
569             attributes[i].STEPread( in, instance_set, idIncr, currSch, strict );
570             in >> c; // read the , or ) following the attr read
571 
572             severe = attributes[i].Error().severity();
573 
574             if( severe <= SEVERITY_USERMSG ) {
575                 // if there is some type of error
576                 PrependEntityErrMsg();
577 
578                 // set the severity for this entity
579                 _error.GreaterSeverity( severe );
580                 sprintf( errStr, "  %s :  ", attributes[i].Name() );
581                 _error.AppendToDetailMsg( errStr ); // add attr name
582                 _error.AppendToDetailMsg( attributes[i].Error().DetailMsg() );  // add attr error
583                 _error.AppendToUserMsg( attributes[i].Error().UserMsg() );
584             }
585         }
586 
587         // if technical corrigendum redefined, input is at next attribute value
588         // if pre-technical corrigendum redefined, don't process
589         if( ( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) ||
590                 !useTechCor ) &&
591                 !( ( c == ',' ) || ( c == ')' ) ) ) { //  input is not a delimiter
592             PrependEntityErrMsg();
593 
594             _error.AppendToDetailMsg(
595                 "Delimiter expected after attribute value.\n" );
596             if( !useTechCor ) {
597                 _error.AppendToDetailMsg(
598                     "I.e. since using pre-technical corrigendum, redefined " );
599                 _error.AppendToDetailMsg(
600                     "attribute is mapped as an asterisk so needs delimiter.\n" );
601             }
602             CheckRemainingInput( in, &_error, "ENTITY", ",)" );
603             if( !in.good() ) {
604                 return _error.severity();
605             }
606             if( _error.severity() <= SEVERITY_INPUT_ERROR ) {
607                 return _error.severity();
608             }
609         } else if( c == ')' ) {
610             while( i < n - 1 ) {
611                 i++; // check if following attributes are redefined
612                 if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) ) {
613                     PrependEntityErrMsg();
614                     _error.AppendToDetailMsg( "Missing attribute value[s].\n" );
615                     // recoverable error
616                     _error.GreaterSeverity( SEVERITY_WARNING );
617                     return _error.severity();
618                 }
619                 i++;
620             }
621             return _error.severity();
622         }
623     }
624     STEPread_error( c, i, in, currSch );
625 //  code fragment imported from STEPread_error
626 //  for some currently unknown reason it was commented out of STEPread_error
627     errStr[0] = '\0';
628     in.clear();
629     int foundEnd = 0;
630     std::string tmp;
631     tmp = "";
632 
633     // Search until a close paren is found followed by (skipping optional
634     // whitespace) a semicolon
635     while( in.good() && !foundEnd ) {
636         while( in.good() && ( c != ')' ) ) {
637             in.get( c );
638             tmp += c;
639         }
640         if( in.good() && ( c == ')' ) ) {
641             in >> ws; // skip whitespace
642             in.get( c );
643             tmp += c;
644             if( c == ';' ) {
645                 foundEnd = 1;
646             }
647         }
648     }
649     _error.AppendToDetailMsg( tmp.c_str() );
650     sprintf( errStr, "\nfinished reading #%d\n", STEPfile_id );
651     _error.AppendToDetailMsg( errStr );
652 // end of imported code
653     return _error.severity();
654 }
655 
656 /// read an entity reference and return a pointer to the SDAI_Application_instance
ReadEntityRef(istream & in,ErrorDescriptor * err,const char * tokenList,InstMgrBase * instances,int addFileId)657 SDAI_Application_instance * ReadEntityRef( istream & in, ErrorDescriptor * err, const char * tokenList,
658         InstMgrBase * instances, int addFileId ) {
659     char c;
660     char errStr[BUFSIZ];
661     errStr[0] = '\0';
662 
663     in >> ws;
664     in >> c;
665     switch( c ) {
666         case '@':
667             err->AppendToDetailMsg( "Use of @ instead of # to identify entity.\n" );
668             err->GreaterSeverity( SEVERITY_WARNING );
669             // no break statement here on purpose
670         case '#': {
671             int id = -1;
672             in >>  id;
673             if( in.fail() ) { //  there's been an error in input
674                 sprintf( errStr, "Invalid entity reference value.\n" );
675                 err->AppendToDetailMsg( errStr );
676                 err->AppendToUserMsg( errStr );
677                 err->GreaterSeverity( SEVERITY_WARNING );
678                 CheckRemainingInput( in, err, "Entity Reference", tokenList );
679                 return S_ENTITY_NULL;
680             } else { // found an entity id
681                 // check to make sure garbage does not follow the id
682                 CheckRemainingInput( in, err, "Entity Reference", tokenList );
683 
684                 id += addFileId;
685                 if( !instances ) {
686                     cerr << "Internal error:  " << __FILE__ <<  __LINE__
687                          << "\n" << _POC_ "\n";
688                     sprintf( errStr,
689                              "STEPread_reference(): %s - entity #%d %s.\n",
690                              "BUG - cannot read reference without the InstMgr",
691                              id, "is unknown" );
692                     err->AppendToDetailMsg( errStr );
693                     err->AppendToUserMsg( errStr );
694                     err->GreaterSeverity( SEVERITY_BUG );
695                     return S_ENTITY_NULL;
696                 }
697 
698                 //  lookup which object has id as its instance id
699                 SDAI_Application_instance * inst;
700                 /* If there is a ManagerNode it should have a SDAI_Application_instance */
701                 MgrNodeBase * mn = 0;
702                 mn = instances->FindFileId( id );
703                 if( mn ) {
704                     inst =  mn->GetSTEPentity() ;
705                     if( inst ) {
706                         return ( inst );
707                     } else {
708                         cerr << "Internal error:  " << __FILE__ <<  __LINE__
709                              << "\n" << _POC_ "\n";
710                         sprintf( errStr,
711                                  "STEPread_reference(): %s - entity #%d %s.\n",
712                                  "BUG - MgrNode::GetSTEPentity returned NULL pointer",
713                                  id, "is unknown" );
714                         err->AppendToDetailMsg( errStr );
715                         err->AppendToUserMsg( errStr );
716                         err->GreaterSeverity( SEVERITY_BUG );
717                         return S_ENTITY_NULL;
718                     }
719                 } else {
720                     sprintf( errStr, "Reference to non-existent ENTITY #%d.\n",
721                              id );
722                     err->AppendToDetailMsg( errStr );
723                     err->AppendToUserMsg( errStr );
724                     err->GreaterSeverity( SEVERITY_WARNING );
725                     return S_ENTITY_NULL;
726                 }
727             }
728         }
729         default: {
730             in.putback( c );
731             // read past garbage up to delim in tokenList
732             // if tokenList is null it will not read anything
733             CheckRemainingInput( in, err, "Entity Reference", tokenList );
734             return S_ENTITY_NULL;
735         }
736     }
737 }
738 
739 /// read an entity reference and return a pointer to the SDAI_Application_instance
ReadEntityRef(const char * s,ErrorDescriptor * err,const char * tokenList,InstMgrBase * instances,int addFileId)740 SDAI_Application_instance * ReadEntityRef( const char * s, ErrorDescriptor * err, const char * tokenList,
741         InstMgrBase * instances, int addFileId ) {
742     istringstream in( ( char * )s );
743     return ReadEntityRef( in, err, tokenList, instances, addFileId );
744 }
745 
746 /// return SEVERITY_NULL if se's entity type matches the supplied entity type
EntityValidLevel(SDAI_Application_instance * se,const TypeDescriptor * ed,ErrorDescriptor * err)747 Severity EntityValidLevel( SDAI_Application_instance * se,
748                            const TypeDescriptor * ed, // entity type that entity se needs
749                            // to match. (this must be an
750                            // EntityDescriptor)
751                            ErrorDescriptor * err ) {
752     char messageBuf [BUFSIZ];
753     messageBuf[0] = '\0';
754 
755     if( !ed || ( ed->NonRefType() != ENTITY_TYPE ) ) {
756         err->GreaterSeverity( SEVERITY_BUG );
757         sprintf( messageBuf,
758                  " BUG: EntityValidLevel() called with %s",
759                  "missing or invalid EntityDescriptor\n" );
760         err->AppendToUserMsg( messageBuf );
761         err->AppendToDetailMsg( messageBuf );
762         cerr << "Internal error:  " << __FILE__ << ":" <<  __LINE__
763              << "\n" << _POC_ "\n";
764         return SEVERITY_BUG;
765     }
766     if( !se || ( se == S_ENTITY_NULL ) ) {
767         err->GreaterSeverity( SEVERITY_BUG );
768         sprintf( messageBuf,
769                  " BUG: EntityValidLevel() called with null pointer %s\n",
770                  "for SDAI_Application_instance argument." );
771         err->AppendToUserMsg( messageBuf );
772         err->AppendToDetailMsg( messageBuf );
773         cerr << "Internal error:  " << __FILE__ << ":" <<  __LINE__
774              << "\n" << _POC_ "\n";
775         return SEVERITY_BUG;
776     }
777 
778     // DAVE: Can an entity be used in an Express TYPE so that this
779     // EntityDescriptor would have type REFERENCE_TYPE -- it looks like NO
780 
781     else if( se->getEDesc() ) {
782         // is se a descendant of ed?
783         if( se->getEDesc()->IsA( ed ) ) {
784             return SEVERITY_NULL;
785         } else {
786             if( se->IsComplex() ) {
787                 // This way assumes that the complex has all it's parts i.e. the
788                 // complete hierarchy so it should be able to find ed's part if
789                 // it is an ed.
790                 STEPcomplex * sc = ( ( STEPcomplex * )se )->sc;
791                 if( sc->EntityExists( ed->Name() ) ) {
792                     return SEVERITY_NULL;
793                 }
794             }
795             err->GreaterSeverity( SEVERITY_WARNING );
796             sprintf( messageBuf,
797                      " Entity #%d exists but is not a %s or descendant.\n",
798                      se->STEPfile_id, ed->Name() );
799             err->AppendToUserMsg( messageBuf );
800             err->AppendToDetailMsg( messageBuf );
801             return SEVERITY_WARNING;
802         }
803     } else {
804         err->GreaterSeverity( SEVERITY_BUG );
805         sprintf( messageBuf,
806                  " BUG: EntityValidLevel(): SDAI_Application_instance #%d has a %s",
807                  se->STEPfile_id, "missing or invalid EntityDescriptor\n" );
808         err->AppendToUserMsg( messageBuf );
809         err->AppendToDetailMsg( messageBuf );
810         cerr << "Internal error:  " << __FILE__ <<  __LINE__
811              << "\n" << _POC_ "\n";
812         return SEVERITY_BUG;
813     }
814 }
815 
816 /**
817  * return 1 if attrValue has the equivalent of a null value.
818  * DAVE: Is this needed will sscanf return 1 if assignment suppression is used?
819  */
SetErrOnNull(const char * attrValue,ErrorDescriptor * error)820 int SetErrOnNull( const char * attrValue, ErrorDescriptor * error ) {
821     char scanBuf[BUFSIZ];
822     scanBuf[0] = '\0';
823 
824     std::stringstream fmtstr;
825     fmtstr << " %" << BUFSIZ -1 << "s ";
826     //fmtstr contains " %ns " where n is BUFSIZ -1
827 
828     int numFound = sscanf( ( char * )attrValue , fmtstr.str().c_str() , scanBuf );
829 
830     if( numFound == EOF ) {
831         error->GreaterSeverity( SEVERITY_INCOMPLETE );
832         return 1;
833     }
834     return 0;
835 }
836 
837 /**
838 ** return SEVERITY_NULL if attrValue has a valid entity reference
839 ** This function accepts an entity reference in two forms that is with or
840 ** without the # sign: e.g. either #23 or 23 will be read.
841 ** If non-whitespace characters follow the entity reference an error is set.
842 */
EntityValidLevel(const char * attrValue,const TypeDescriptor * ed,ErrorDescriptor * err,InstMgrBase * im,int clearError)843 Severity EntityValidLevel( const char * attrValue, // string contain entity ref
844                            const TypeDescriptor * ed, // entity type that entity in
845                            // attrValue (if it exists) needs
846                            // to match. (this must be an
847                            // EntityDescriptor)
848                            ErrorDescriptor * err, InstMgrBase * im, int clearError ) {
849     char tmp [BUFSIZ];
850     tmp[0] = '\0';
851     char messageBuf [BUFSIZ];
852     messageBuf[0] = '\0';
853     std::stringstream fmtstr1, fmtstr2;
854 
855     if( clearError ) {
856         err->ClearErrorMsg();
857     }
858 
859     int fileId;
860     MgrNodeBase * mn = 0;
861 
862     // fmtstr1 contains "#%d %ns" where n is BUFSIZ-1
863     fmtstr1 << " #%d %" << BUFSIZ - 1 << "s ";
864 
865     // fmtstr2 contains "%d %ns" where n is BUFSIZ-1
866     fmtstr2 << " %d %" << BUFSIZ - 1 << "s ";
867 
868     // check for both forms:  #id or id
869     int found1 = sscanf( ( char * )attrValue, fmtstr1.str().c_str() , &fileId, tmp );
870     int found2 = sscanf( ( char * )attrValue, fmtstr2.str().c_str() , &fileId, tmp );
871 
872     if( ( found1 > 0 ) || ( found2 > 0 ) ) {
873         if( ( found1 == 2 ) || ( found2 == 2 ) ) {
874             sprintf( messageBuf,
875                      " Attribute's Entity Reference %s is %s data \'%s\'.\n",
876                      attrValue, "followed by invalid", tmp );
877             err->AppendToUserMsg( messageBuf );
878             err->AppendToDetailMsg( messageBuf );
879             err->GreaterSeverity( SEVERITY_WARNING );
880         }
881         mn = im->FindFileId( fileId );
882         if( mn ) {
883             SDAI_Application_instance * se = mn->GetSTEPentity();
884             return EntityValidLevel( se, ed, err );
885         } else {
886             sprintf( messageBuf,
887                      " Attribute's Entity Reference %s does not exist.\n",
888                      attrValue );
889             err->AppendToUserMsg( messageBuf );
890             err->AppendToDetailMsg( messageBuf );
891             err->GreaterSeverity( SEVERITY_WARNING );
892             return SEVERITY_WARNING;
893         }
894     }
895 
896     // if the attrValue contains no value return
897     if( SetErrOnNull( attrValue, err ) ) {
898         return err->severity();
899     }
900 
901     sprintf( messageBuf, "Invalid attribute entity reference value: '%s'.\n",
902              attrValue );
903     err->AppendToUserMsg( messageBuf );
904     err->AppendToDetailMsg( messageBuf );
905     err->GreaterSeverity( SEVERITY_WARNING );
906     return SEVERITY_WARNING;
907 }
908 
909 /**************************************************************//**
910 ** Description:  used to cycle through the list of attributes
911 ** Side Effects:  increments the current position in the attribute list
912 ** Status:  untested 7/31/90
913 ** \Returns  reference to an attribute pointer
914 ******************************************************************/
NextAttribute()915 STEPattribute * SDAI_Application_instance::NextAttribute()  {
916     int i = AttributeCount();
917     ++_cur;
918     if( i < _cur ) {
919         return 0;
920     }
921     return &attributes [_cur - 1];
922 }
923 
AttributeCount()924 int SDAI_Application_instance::AttributeCount()  {
925     return  attributes.list_length();
926 }
927 
getInvAttr(const Inverse_attribute * const ia) const928 const iAstruct SDAI_Application_instance::getInvAttr( const Inverse_attribute * const ia ) const {
929     iAstruct ias;
930     memset( &ias, 0, sizeof ias );
931     iAMap_t::const_iterator it = iAMap.find( ia );
932     if( it != iAMap.end() ) {
933         ias = (*it).second;
934     }
935     return ias;
936 }
937 
getInvAttr(const char * name) const938 const SDAI_Application_instance::iAMap_t::value_type SDAI_Application_instance::getInvAttr( const char * name ) const {
939     iAMap_t::const_iterator it = iAMap.begin();
940     for( ; it != iAMap.end(); ++it ) {
941         if( 0 == strcmp( it->first->Name(), name) ) {
942             return *it;
943         }
944     }
945     iAstruct z;
946     memset( &z, 0, sizeof z );
947     iAMap_t::value_type nil( NULL, z );
948     return nil;
949 }
950 
setInvAttr(const Inverse_attribute * const ia,const iAstruct ias)951 void SDAI_Application_instance::setInvAttr( const Inverse_attribute * const ia, const iAstruct ias )  {
952     iAMap_t::iterator it = iAMap.find(ia);
953     if( it != iAMap.end() ) {
954         it->second = ias;
955     } else {
956         iAMap.insert( iAMap_t::value_type( ia, ias ) );
957     }
958 }
959