1 /*
2 * NIST STEP Core Class Library
3 * clstepcore/STEPattribute.cc
4 * April 1997
5 * K. C. Morris
6 * David Sauder
7 
8 * Development of this software was funded by the United States Government,
9 * and is not subject to copyright.
10 */
11 
12 #include <iomanip>
13 #include <sstream>
14 #include <string>
15 
16 #include <read_func.h>
17 #include <STEPattribute.h>
18 #include <instmgr.h>
19 #include <STEPundefined.h>
20 #include <STEPaggregate.h>
21 #include <ExpDict.h>
22 #include <sdai.h>
23 #include "sc_memmgr.h"
24 
25 // REAL_NUM_PRECISION is defined in STEPattribute.h, and is also used
26 // in aggregate real handling (STEPaggregate.cc)  -- IMS 6 Jun 95
27 const int Real_Num_Precision = REAL_NUM_PRECISION;
28 
29 /**************************************************************//**
30 ** \class STEPattribute
31 **    Functions for manipulating attribute
32 **
33 **  FIXME KNOWN BUGS:
34 **    -- error reporting does not include line number information
35 **    -- null attributes are only handled through the attribute pointer class
36 **       direct access of a null attribute will not indicate whether the
37 **       attribute is null in all cases (although a null value is available
38 **       for entities and enumerations.)
39 **/
40 
41 
42 ///////////////////////////////////////////////////////////////////////////////
43 ///////////////////////////////////////////////////////////////////////////////
44 // STEPattribute Functions
45 ///////////////////////////////////////////////////////////////////////////////
46 ///////////////////////////////////////////////////////////////////////////////
47 
48 /// the value of the attribute is assigned from the supplied string
StrToVal(const char * s,InstMgrBase * instances,int addFileId)49 Severity STEPattribute::StrToVal( const char * s, InstMgrBase * instances, int addFileId ) {
50     if( _redefAttr )  {
51         return _redefAttr->StrToVal( s, instances, addFileId );
52     }
53 
54     _error.ClearErrorMsg(); // also sets Severity to SEVERITY_NULL
55 
56     //  set the value to be null (reinitialize the attribute value)
57     set_null();
58 
59     int nullable = ( aDesc->Optional().asInt() == BTrue );
60 
61     // an empty str gets assigned NULL
62     if( !s ) {
63         if( nullable || IsDerived() ) { // if it is derived it doesn't
64             return SEVERITY_NULL;    // matter if it is null DAS
65         } else {
66             _error.severity( SEVERITY_INCOMPLETE );
67             return SEVERITY_INCOMPLETE;
68         }
69     }
70     if( s[0] == '\0' ) {
71         if( NonRefType() == STRING_TYPE ) {
72             // this is interpreted as a string with no value i.e. "".
73             *( ptr.S ) = s; // using string class - don't need to declare space
74             return SEVERITY_NULL;
75         }
76         if( nullable || IsDerived() ) { // if it is derived it doesn't
77             return SEVERITY_NULL;    // matter if it is null DAS
78         } else  {
79             _error.severity( SEVERITY_INCOMPLETE );
80             return SEVERITY_INCOMPLETE;
81         }
82     }
83 
84     //  an overridden attribute always has a \'*\' value
85     if( IsDerived() ) { // check to see if value contains: optional space,
86         // followed by *, followed by optional space
87         const char * tmpSptr = s;
88         while( isspace( *tmpSptr ) ) {
89             tmpSptr++;
90         }
91         if( *tmpSptr == '*' ) {
92             tmpSptr++;
93             char tmpC;
94             int charsFound = sscanf( tmpSptr, "%c", &tmpC );
95             if( charsFound == EOF ) { // no non-white chars followed the *
96                 return SEVERITY_NULL;
97             }
98         }
99         _error.AppendToDetailMsg(
100             "Derived attribute must have \'*\' for its value.\n" );
101         return _error.severity( SEVERITY_INPUT_ERROR );
102     }
103 
104     istringstream in( ( char * )s ); // sz defaults to length of s
105 
106     // read in value for attribute
107     switch( NonRefType() ) {
108         case INTEGER_TYPE: {
109             ReadInteger( *( ptr.i ), s, &_error, 0 );
110             break;
111         }
112         case REAL_TYPE: {
113             ReadReal( *( ptr.r ), s, &_error, 0 );
114             break;
115         }
116         case NUMBER_TYPE: {
117             ReadNumber( *( ptr.r ), s, &_error, 0 );
118             break;
119         }
120 
121         case ENTITY_TYPE: {
122             STEPentity * se = ReadEntityRef( s, &_error, 0, instances, addFileId );
123             if( se != S_ENTITY_NULL ) {
124                 if( EntityValidLevel( se, aDesc->NonRefTypeDescriptor(),
125                                       &_error )
126                         == SEVERITY_NULL ) {
127                     *( ptr.c ) = se;
128                 } else {
129                     *( ptr.c ) = S_ENTITY_NULL;
130                 }
131             } else {
132                 *( ptr.c ) = S_ENTITY_NULL;
133             }
134             break;
135         }
136 
137         case BINARY_TYPE: {
138             ptr.b->StrToVal( s, &_error ); // call class SDAI_Binary::StrToVal()
139             break;
140         }
141         case STRING_TYPE: {
142             *( ptr.S ) = s; // using string class - don't need to declare space
143             break;
144         }
145 
146         case BOOLEAN_TYPE:
147         case LOGICAL_TYPE:
148         case ENUM_TYPE: {
149             ptr.e->StrToVal( s, &_error, nullable );
150             break;
151         }
152 
153         case AGGREGATE_TYPE:
154         case ARRAY_TYPE:      // DAS
155         case BAG_TYPE:        // DAS
156         case SET_TYPE:        // DAS
157         case LIST_TYPE:       // DAS
158             ptr.a -> StrToVal( s, &_error,
159                                aDesc -> AggrElemTypeDescriptor(),
160                                instances, addFileId );
161             break;
162 
163         case SELECT_TYPE:
164             if( _error.severity( ptr.sh->STEPread( in, &_error, instances, 0 ) )
165                     != SEVERITY_NULL ) {
166                 _error.AppendToDetailMsg( ptr.sh ->Error() );
167             }
168             break;
169 
170 //      case UNKNOWN_TYPE: // should never have this case
171         case GENERIC_TYPE:
172         default:
173             // other cases are the same for StrToVal and file
174             return STEPread( in, instances, addFileId );
175     }
176     return _error.severity();
177 }
178 
179 
180 /**************************************************************//**
181 ** \fn STEPread
182 ** \brief Reads attribute value from in, formatted as P21 file.
183 ** The value of the attribute is read from istream. The format
184 ** expected is STEP exchange file.
185 **
186 ** Accepts '$' or nothing as value for OPTIONAL ATTRIBUTE, since
187 ** this function is used for reading files in both old an new
188 ** formats.
189 **
190 ** Does not read the delimiter separating individual attributes (i.e. ',') or
191 ** the delim separating the last attribute from the end of the entity (')').
192 **
193 ** \returns  Severity, which indicates success or failure
194 **         value >= SEVERITY_WARNING means program can continue parsing input,
195 **         value <= SEVERITY_INPUT_ERROR  is fatal read error
196 ******************************************************************/
STEPread(istream & in,InstMgrBase * instances,int addFileId,const char * currSch,bool strict)197 Severity STEPattribute::STEPread( istream & in, InstMgrBase * instances, int addFileId,
198                                   const char * currSch, bool strict ) {
199 
200     // The attribute has been redefined by the attribute pointed
201     // to by _redefAttr so write the redefined value.
202     if( _redefAttr )  {
203         return _redefAttr->STEPread( in, instances, addFileId, currSch );
204     }
205 
206     _error.ClearErrorMsg(); // also sets Severity to SEVERITY_NULL
207 
208     //  set the value to be null (reinitialize the attribute value)
209     set_null();
210 
211     in >> ws; // skip whitespace
212     char c = in.peek();
213 
214     if( IsDerived() ) {
215         if( c == '*' ) {
216             in.get( c ); // take * off the istream
217             _error.severity( SEVERITY_NULL );
218         } else {
219             _error.severity( SEVERITY_WARNING );
220             _error.AppendToDetailMsg( "  WARNING: attribute '" );
221             _error.AppendToDetailMsg( aDesc->Name() );
222             _error.AppendToDetailMsg( "' of type '" );
223             _error.AppendToDetailMsg( aDesc->TypeName() );
224             _error.AppendToDetailMsg( "' - missing asterisk for derived attribute.\n" );
225         }
226         CheckRemainingInput( in, &_error, aDesc->TypeName(), ",)" );
227         return _error.severity();
228     }
229     PrimitiveType attrBaseType = NonRefType();
230 
231     //  check for NULL or derived attribute value, return if either
232     switch( c ) {
233         case '$':
234         case ',':
235         case ')':
236             if( c == '$' ) {
237                 in.ignore();
238                 CheckRemainingInput( in, &_error, aDesc->TypeName(), ",)" );
239             }
240             if( Nullable() )  {
241                 _error.severity( SEVERITY_NULL );
242             } else if( !strict ) {
243                 std::string fillerValue;
244                 // we aren't in strict mode, so find out the type of the missing attribute and insert a suitable value.
245                 ErrorDescriptor err; //this will be discarded
246                 switch( attrBaseType ) {
247                     case INTEGER_TYPE: {
248                         fillerValue = "'0',";
249                         ReadInteger( *( ptr.i ), fillerValue.c_str(), &err, ",)" );
250                         break;
251                     }
252                     case REAL_TYPE: {
253                         fillerValue = "'0.0',";
254                         ReadReal( *( ptr.r ), fillerValue.c_str(), &err, ",)" );
255                         break;
256                     }
257                     case NUMBER_TYPE: {
258                         fillerValue = "'0',";
259                         ReadNumber( *( ptr.r ), fillerValue.c_str(), &err, ",)" );
260                         break;
261                     }
262                     case STRING_TYPE: {
263                         fillerValue = "'',";
264                         *( ptr.S ) = "''";
265                         break;
266                     }
267                     default: { //do not know what a good value would be for other types
268                         _error.severity( SEVERITY_INCOMPLETE );
269                         _error.AppendToDetailMsg( " missing and required\n" );
270                         return _error.severity();
271                     }
272                 }
273                 if( err.severity() <= SEVERITY_INCOMPLETE ) {
274                     _error.severity( SEVERITY_BUG );
275                     _error.AppendToDetailMsg( " Error in STEPattribute::STEPread()\n" );
276                     return _error.severity();
277                 }
278                 //create a warning. SEVERITY_WARNING makes more sense to me, but is considered more severe than SEVERITY_INCOMPLETE
279                 _error.severity( SEVERITY_USERMSG );
280                 _error.AppendToDetailMsg( " missing and required. For compatibility, replacing with " );
281                 _error.AppendToDetailMsg( fillerValue.substr( 0, fillerValue.length() - 1 ) );
282                 _error.AppendToDetailMsg( ".\n" );
283             } else {
284                 _error.severity( SEVERITY_INCOMPLETE );
285                 _error.AppendToDetailMsg( " missing and required\n" );
286             }
287             return _error.severity();
288     }
289 
290     switch( attrBaseType ) {
291         case INTEGER_TYPE: {
292             ReadInteger( *( ptr.i ), in, &_error, ",)" );
293             return _error.severity();
294         }
295         case REAL_TYPE: {
296             ReadReal( *( ptr.r ), in, &_error, ",)" );
297             return _error.severity();
298         }
299         case NUMBER_TYPE: {
300             ReadNumber( *( ptr.r ), in, &_error, ",)" );
301             return _error.severity();
302         }
303         case STRING_TYPE: {
304             ptr.S->STEPread( in, &_error );
305             CheckRemainingInput( in, &_error, "string", ",)" );
306             return _error.severity();
307         }
308         case BINARY_TYPE: {
309             // call class SDAI_Binary::STEPread()
310             ptr.b->STEPread( in, &_error );
311             CheckRemainingInput( in, &_error, "binary", ",)" );
312             return _error.severity();
313         }
314         case BOOLEAN_TYPE: {
315             ptr.e->STEPread( in, &_error,  Nullable() );
316             CheckRemainingInput( in, &_error, "boolean", ",)" );
317             return _error.severity();
318         }
319         case LOGICAL_TYPE: {
320             ptr.e->STEPread( in, &_error,  Nullable() );
321             CheckRemainingInput( in, &_error, "logical", ",)" );
322             return _error.severity();
323         }
324         case ENUM_TYPE: {
325             ptr.e->STEPread( in, &_error,  Nullable() );
326             CheckRemainingInput( in, &_error, "enumeration", ",)" );
327             return _error.severity();
328         }
329         case AGGREGATE_TYPE:
330         case ARRAY_TYPE:      // DAS
331         case BAG_TYPE:        // DAS
332         case SET_TYPE:        // DAS
333         case LIST_TYPE: {     // DAS
334             ptr.a->STEPread( in, &_error,
335                              aDesc->AggrElemTypeDescriptor(),
336                              instances, addFileId, currSch );
337 
338             // cannot recover so give up and let STEPentity recover
339             if( _error.severity() < SEVERITY_WARNING ) {
340                 return _error.severity();
341             }
342 
343             // check for garbage following the aggregate
344             CheckRemainingInput( in, &_error, "aggregate", ",)" );
345             return _error.severity();
346         }
347         case ENTITY_TYPE: {
348             STEPentity * se = ReadEntityRef( in, &_error, ",)", instances,
349                                              addFileId );
350             if( se != S_ENTITY_NULL ) {
351                 if( EntityValidLevel( se,
352                                       aDesc->NonRefTypeDescriptor(),
353                                       &_error ) == SEVERITY_NULL ) {
354                     *( ptr.c ) = se;
355                 } else {
356                     *( ptr.c ) = S_ENTITY_NULL;
357                 }
358             } else {
359                 *( ptr.c ) = S_ENTITY_NULL;
360             }
361             return _error.severity();
362 
363         }
364         case SELECT_TYPE:
365             if( _error.severity( ptr.sh->STEPread( in, &_error, instances, 0,
366                                                    addFileId, currSch ) )
367                     != SEVERITY_NULL ) {
368                 _error.AppendToDetailMsg( ptr.sh ->Error() );
369             }
370             CheckRemainingInput( in, &_error, "select", ",)" );
371             return _error.severity();
372 
373         case GENERIC_TYPE: {
374             cerr << "Internal error:  " << __FILE__ <<  __LINE__
375                  << "\n" << _POC_ "\n";
376             _error.GreaterSeverity( SEVERITY_BUG );
377             return _error.severity();
378         }
379 
380         case UNKNOWN_TYPE:
381         case REFERENCE_TYPE:
382         default: {
383             // bug
384             cerr << "Internal error:  " << __FILE__ <<  __LINE__
385                  << "\n" << _POC_ "\n";
386             _error.GreaterSeverity( SEVERITY_BUG );
387             return _error.severity();
388         }
389     }
390 }
391 
392 /*****************************************************************//**
393  ** \fn asStr
394  ** \param currSch - used for select type writes.  See commenting in SDAI_Select::STEPwrite().
395  ** \returns the value of the attribute
396  ** Status:  complete 3/91
397  *********************************************************************/
asStr(const char * currSch) const398 std::string STEPattribute::asStr( const char * currSch ) const {
399     ostringstream ss;
400     std::string str;
401 
402     // The attribute has been derived by a subtype's attribute
403     if( IsDerived() )  {
404         str = "*";
405         return str;
406     }
407 
408     // The attribute has been redefined by the attribute pointed
409     // to by _redefAttr so write the redefined value.
410     if( _redefAttr )  {
411         return _redefAttr->asStr( currSch );
412     }
413 
414     if( is_null() )  {
415         return str;
416     }
417 
418     switch( NonRefType() ) {
419         case INTEGER_TYPE:
420             ss << *( ptr.i );
421             str += ss.str();
422             break;
423 
424         case NUMBER_TYPE:
425         case REAL_TYPE:
426 
427             ss.precision( ( int ) Real_Num_Precision );
428             ss << *( ptr.r );
429             str += ss.str();
430             break;
431 
432         case ENTITY_TYPE:
433             // print instance id only if not empty pointer
434             // and has value assigned
435             if( ( *( ptr.c ) == S_ENTITY_NULL ) || ( *( ptr.c ) == 0 ) ) {
436                 break;
437             } else {
438                 ( *( ptr.c ) )->STEPwrite_reference( str );
439             }
440             break;
441 
442         case BINARY_TYPE:
443             if( !( ptr.b->empty() ) ) {
444                 ptr.b->STEPwrite( str );
445             }
446             break;
447 
448         case STRING_TYPE:
449             if( !( ( ptr.S )->empty() ) ) {
450                 ptr.S->asStr( str );
451             }
452             break;
453 
454         case AGGREGATE_TYPE:
455         case ARRAY_TYPE:      // DAS
456         case BAG_TYPE:        // DAS
457         case SET_TYPE:        // DAS
458         case LIST_TYPE:       // DAS
459             ptr.a->asStr( str );
460             break;
461 
462         case ENUM_TYPE:
463         case BOOLEAN_TYPE:
464         case LOGICAL_TYPE:
465             ptr.e->asStr( str );
466             break;
467 
468         case SELECT_TYPE:
469             ptr.sh->STEPwrite( str, currSch );
470             break;
471 
472         case REFERENCE_TYPE:
473         case GENERIC_TYPE:
474             cerr << "Internal error:  " << __FILE__ <<  __LINE__
475                  << "\n" << _POC_ "\n";
476             str.clear();
477             break;
478 
479         case UNKNOWN_TYPE:
480         default:
481             ptr.u->asStr( str );
482     }
483     return str;
484 }
485 
486 /// write '$' to out, put message in error, write brief error to stderr
STEPwriteError(ostream & out,unsigned int line,const char * desc)487 void STEPattribute::STEPwriteError( ostream & out, unsigned int line, const char* desc ) {
488     out << "$";
489     cerr << "Internal error:  " << __FILE__ << ":" << line << "\n" << _POC_ "\n";
490 
491     _error.GreaterSeverity( SEVERITY_BUG );
492     std::stringstream ss;
493     ss << " Warning: attribute '" << Name() << " : " << TypeName() << "' " << desc << std::endl;
494     _error.AppendToUserMsg( ss.str() );
495     _error.AppendToDetailMsg( ss.str() );
496 }
497 
498 /**
499  * The value of the attribute is printed to the output stream specified by out.
500  * The output is in physical file format.
501  *
502  */
STEPwrite(ostream & out,const char * currSch)503 void STEPattribute::STEPwrite( ostream & out, const char * currSch ) {
504     // The attribute has been derived by a subtype's attribute
505     if( IsDerived() ) {
506         out << "*";
507         return;
508     }
509     // The attribute has been redefined by the attribute pointed
510     // to by _redefAttr so write the redefined value.
511     if( _redefAttr )  {
512         _redefAttr->STEPwrite( out );
513         return;
514     }
515 
516     if( is_null() ) {
517         out << "$";
518         return;
519     }
520 
521     switch( NonRefType() ) {
522         case INTEGER_TYPE:
523             out << *( ptr.i );
524             break;
525 
526         case NUMBER_TYPE:
527         case REAL_TYPE: {
528             WriteReal( *( ptr.r ), out );
529             break;
530         }
531 
532         case ENTITY_TYPE:
533             // print instance id only if not empty pointer
534             if( ( ptr.c == 0 ) || ( *( ptr.c ) == 0 ) ||
535                     // no value was assigned  <-- this would be a BUG
536                     ( *( ptr.c ) == S_ENTITY_NULL ) ) {
537                 STEPwriteError( out, __LINE__, "is null and shouldn't be." );
538             } else {
539                 ( *( ptr.c ) ) -> STEPwrite_reference( out );
540             }
541             break;
542 
543         case STRING_TYPE:
544             // if null pointer or pointer to a string of length zero
545             if( ptr.S ) {
546                 ( ptr.S ) -> STEPwrite( out );
547             } else {
548                 STEPwriteError( out, __LINE__, "should be pointing at an SDAI_String." );
549             }
550             break;
551 
552         case BINARY_TYPE:
553             // if null pointer or pointer to a string of length zero
554             if( ptr.b ) {
555                 ( ptr.b ) -> STEPwrite( out );
556             } else {
557                 STEPwriteError( out, __LINE__, "should be pointing at an SDAI_Binary." );
558             }
559             break;
560 
561         case AGGREGATE_TYPE:
562         case ARRAY_TYPE:      // DAS
563         case BAG_TYPE:        // DAS
564         case SET_TYPE:        // DAS
565         case LIST_TYPE:       // DAS
566             ptr.a -> STEPwrite( out, currSch );
567             break;
568 
569         case ENUM_TYPE:
570         case BOOLEAN_TYPE:
571         case LOGICAL_TYPE:
572             if( ptr.e ) {
573                 ptr.e -> STEPwrite( out );
574             } else {
575                 STEPwriteError( out, __LINE__, "should be pointing at a SDAI_Enum class." );
576             }
577             break;
578 
579         case SELECT_TYPE:
580             if( ptr.sh ) {
581                 ptr.sh -> STEPwrite( out, currSch );
582             } else {
583                 STEPwriteError( out, __LINE__, "should be pointing at a SDAI_Select class." );
584             }
585             break;
586 
587         case REFERENCE_TYPE:
588         case GENERIC_TYPE:
589             cerr << "Internal error:  " << __FILE__ << ":" <<  __LINE__ << "\n" << _POC_ "\n";
590             _error.GreaterSeverity( SEVERITY_BUG );
591             return;
592 
593         case UNKNOWN_TYPE:
594         default:
595             ptr.u -> STEPwrite( out );
596             break;
597 
598     }
599 }
600 
601 
ShallowCopy(const STEPattribute * sa)602 void STEPattribute::ShallowCopy( const STEPattribute * sa ) {
603     _mustDeletePtr = false;
604     aDesc = sa->aDesc;
605     refCount = 0;
606     _derive = sa->_derive;
607     _redefAttr = sa->_redefAttr;
608     if( _redefAttr )  {
609         _redefAttr->ShallowCopy( sa );
610     }
611     //Should we just use memcpy()? That would be a true shallowCopy
612     switch( sa->NonRefType() ) {
613         case INTEGER_TYPE:
614             ptr.i = sa->ptr.i;
615             break;
616         case BINARY_TYPE:
617             ptr.b = sa->ptr.b;
618             break;
619         case STRING_TYPE:
620             ptr.S = sa->ptr.S;
621             break;
622         case REAL_TYPE:
623         case NUMBER_TYPE:
624             ptr.r = sa->ptr.r;
625             break;
626         case ENTITY_TYPE:
627             ptr.c = sa->ptr.c;
628             break;
629         case ARRAY_TYPE:      // DAS
630         case BAG_TYPE:        // DAS
631         case SET_TYPE:        // DAS
632         case LIST_TYPE:       // DAS
633             switch( sa->BaseType() ) {
634                 case sdaiAGGR:
635                     ptr.a = new GenericAggregate;
636                     break;
637                 case sdaiINSTANCE:
638                     ptr.a = new EntityAggregate;
639                     break;
640                 case sdaiSELECT:
641                     ptr.a = new SelectAggregate;
642                     break;
643                 case sdaiSTRING:
644                     ptr.a = new StringAggregate;
645                     break;
646                 case sdaiBINARY:
647                     ptr.a = new BinaryAggregate;
648                     break;
649                 case sdaiENUMERATION:
650                     ptr.a = new EnumAggregate;
651                     break;
652                 case sdaiBOOLEAN:
653                     ptr.a = new BOOLEANS;
654                     break;
655                 case sdaiLOGICAL:
656                     ptr.a = new LOGICALS;
657                     break;
658                 case sdaiREAL:
659                 case sdaiNUMBER:
660                     ptr.a = new RealAggregate;
661                     break;
662                 case sdaiINTEGER:
663                     ptr.a = new IntAggregate;
664                     break;
665                 default:
666                     std::cerr << "WARNING: Reached default case for BaseType() in STEPattribute::"
667                                 << "ShallowCopy(). New attribute may be invalid." << std::endl;
668                     ptr.a = new STEPaggregate;
669                     break;
670             }
671             ptr.a->ShallowCopy( *( sa->ptr.a ) );
672             _mustDeletePtr = true;
673             break;
674         case SELECT_TYPE:
675             ptr.sh = sa->ptr.sh;
676             break;
677         case BOOLEAN_TYPE:
678             ptr.e = new SDAI_BOOLEAN;
679             ptr.e->put( sa->ptr.e->asInt() );
680             _mustDeletePtr = true;
681             break;
682         case LOGICAL_TYPE:
683             ptr.e = new SDAI_LOGICAL;
684             ptr.e->put( sa->ptr.e->asInt() );
685             _mustDeletePtr = true;
686             break;
687 
688         case AGGREGATE_TYPE:
689         case ENUM_TYPE:
690         default:
691             std::cerr << "WARNING: Reached default case for NonRefType() in STEPattribute::"
692                         << "ShallowCopy(). New attribute may be invalid." << std::endl;
693             memcpy( & ptr, & ( sa->ptr ), sizeof( sa->ptr ) );
694             break;
695     }
696 }
697 
698 /**
699  * for a string attribute this means, make it not exist i.e. SDAI_String
700  * will exist in member variable ptr but SDAI_string will be told to report
701  * as not containing a value (even a value of no chars).
702  */
set_null()703 Severity STEPattribute::set_null() {
704     if( _redefAttr )  {
705         return _redefAttr->set_null();
706     }
707     switch( NonRefType() ) {
708         case INTEGER_TYPE:
709             *( ptr.i ) = S_INT_NULL;
710             break;
711 
712         case NUMBER_TYPE:
713             *( ptr.r ) = S_NUMBER_NULL;
714             break;
715 
716         case REAL_TYPE:
717             *( ptr.r ) = S_REAL_NULL;
718             break;
719 
720         case ENTITY_TYPE:
721             *( ptr.c ) = S_ENTITY_NULL;
722             break;
723 
724         case STRING_TYPE:
725             ptr.S->clear();
726             break;
727 
728         case BINARY_TYPE:
729             ptr.b ->clear();
730             break;
731 
732         case AGGREGATE_TYPE:
733         case ARRAY_TYPE:      // DAS
734         case BAG_TYPE:        // DAS
735         case SET_TYPE:        // DAS
736         case LIST_TYPE: {     // DAS
737             ptr.a -> Empty();
738             break;
739         }
740 
741         case ENUM_TYPE:
742         case BOOLEAN_TYPE:
743         case LOGICAL_TYPE:
744             ptr.e -> set_null();
745             break;
746 
747         case SELECT_TYPE:
748             ptr.sh -> set_null();
749             break;
750 
751         case REFERENCE_TYPE:
752         case GENERIC_TYPE:
753             cerr << "Internal error:  " << __FILE__ << ":" <<  __LINE__ << "\n" << _POC_ "\n";
754             return SEVERITY_BUG;
755 
756         case UNKNOWN_TYPE:
757         default:
758             ptr.u -> set_null();
759             std::stringstream err;
760             err << " Warning: attribute '" << Name() << " : " << TypeName() << " : ";
761             err << Type() << "' - " << "Don't know how to make attribute NULL" << std::endl;
762             _error.AppendToDetailMsg( err.str() );
763             _error.GreaterSeverity( SEVERITY_WARNING );
764             return SEVERITY_WARNING;
765     }
766     if( Nullable() ) {
767         return SEVERITY_NULL;
768     } else {
769         return SEVERITY_INCOMPLETE;
770     }
771 }
772 
773 /**
774  * For a string value this reports whether the string exists (as reported by
775  * SDAI_String ) not whether SDAI_String contains a null string.
776  */
is_null() const777 bool STEPattribute::is_null()  const {
778     if( _redefAttr )  {
779         return _redefAttr->is_null();
780     }
781     switch( NonRefType() ) {
782         case INTEGER_TYPE:
783             return ( *( ptr.i ) == S_INT_NULL );
784 
785         case NUMBER_TYPE:
786             return ( *( ptr.r ) == S_NUMBER_NULL );
787 
788         case REAL_TYPE:
789             return ( *( ptr.r ) == S_REAL_NULL );
790 
791         case ENTITY_TYPE:
792             return ( *( ptr.c ) == S_ENTITY_NULL );
793 
794         case STRING_TYPE:
795             return ( *( ptr.S ) == S_STRING_NULL );
796 
797         case BINARY_TYPE:
798             return ptr.b->empty();
799 
800         case AGGREGATE_TYPE:
801         case ARRAY_TYPE:        // DAS
802         case BAG_TYPE:      // DAS
803         case SET_TYPE:      // DAS
804         case LIST_TYPE: {   // DAS
805             return ( ptr.a -> is_null() );
806         }
807 
808         case ENUM_TYPE:
809         case BOOLEAN_TYPE:
810         case LOGICAL_TYPE:
811             return ( ptr.e -> is_null() );
812 
813         case SELECT_TYPE:
814             return( ptr.sh->is_null() );
815 
816         case REFERENCE_TYPE:
817         case GENERIC_TYPE:
818             cerr << "Internal error:  " << __FILE__ << ": " <<  __LINE__
819                  << "\n" << _POC_ "\n";
820             return SEVERITY_BUG;
821 
822         case UNKNOWN_TYPE:
823         default:
824             return ( ptr.u -> is_null() );
825     }
826 }
827 
828 // these get the attr value
829 
Integer()830 SDAI_Integer * STEPattribute::Integer(){
831     if( NonRefType() == INTEGER_TYPE ) {
832         return ptr.i;
833     }
834     return 0;
835 }
836 
Number()837 SDAI_Real * STEPattribute::Number() {
838     if( NonRefType() == NUMBER_TYPE ) {
839         return ptr.r;
840     }
841     return 0;
842 }
843 
Real()844 SDAI_Real * STEPattribute::Real() {
845     if( NonRefType() == REAL_TYPE ) {
846         return ptr.r;
847     }
848     return 0;
849 }
850 
Entity()851 SDAI_Application_instance * STEPattribute::Entity() {
852     if( NonRefType() == ENTITY_TYPE ) {
853         return *( ptr.c );
854     }
855     return 0;
856 }
857 
String()858 SDAI_String * STEPattribute::String() {
859     if( NonRefType() == STRING_TYPE ) {
860         return ptr.S;
861     }
862     return 0;
863 }
864 
Binary()865 SDAI_Binary * STEPattribute::Binary() {
866     if( NonRefType() == BINARY_TYPE ) {
867         return ptr.b;
868     }
869     return 0;
870 }
871 
Aggregate()872 STEPaggregate * STEPattribute::Aggregate() {
873     if( ( NonRefType() == AGGREGATE_TYPE ) || ( NonRefType() == ARRAY_TYPE ) || ( NonRefType() == BAG_TYPE )
874         || ( NonRefType() == SET_TYPE ) || ( NonRefType() == LIST_TYPE ) ) {
875         return ptr.a;
876     }
877     return 0;
878 }
879 
Boolean()880 SDAI_BOOLEAN * STEPattribute::Boolean() {
881     if( NonRefType() == BOOLEAN_TYPE ) {
882         return ( SDAI_BOOLEAN * ) ptr.e;
883     }
884     return 0;
885 }
886 
Logical()887 SDAI_LOGICAL * STEPattribute::Logical() {
888     if( NonRefType() == LOGICAL_TYPE ) {
889         return ( SDAI_LOGICAL * ) ptr.e;
890     }
891     return 0;
892 }
893 
Enum()894 SDAI_Enum * STEPattribute::Enum() {
895     if( NonRefType() == ENUM_TYPE ) {
896         return ptr.e;
897     }
898     return 0;
899 }
900 
Select()901 SDAI_Select * STEPattribute::Select() {
902     if( NonRefType() == SELECT_TYPE ) {
903         return ptr.sh;
904     }
905     return 0;
906 }
907 
Undefined()908 SCLundefined * STEPattribute::Undefined() {
909     if( ( NonRefType() != REFERENCE_TYPE ) && ( NonRefType() != GENERIC_TYPE ) ) {
910         return ptr.u;
911     }
912     return 0;
913 }
914 
915 // these set the attr value
916 
Integer(SDAI_Integer * n)917 void STEPattribute::Integer( SDAI_Integer * n ) {
918     assert( NonRefType() == INTEGER_TYPE );
919     if( ptr.i ) {
920         *( ptr.i ) = * n;
921     } else {
922         ptr.i = n;
923     }
924 }
925 
Real(SDAI_Real * n)926 void STEPattribute::Real( SDAI_Real * n ) {
927     assert( NonRefType() == REAL_TYPE );
928     if( ptr.r ) {
929         *( ptr.r ) = * n;
930     } else {
931         ptr.r = n;
932     }
933 }
934 
Number(SDAI_Real * n)935 void STEPattribute::Number( SDAI_Real * n ) {
936     assert( NonRefType() == NUMBER_TYPE );
937     if( ptr.r ) {
938         *( ptr.r ) = * n;
939     } else {
940         ptr.r = n;
941     }
942 }
943 
String(SDAI_String * str)944 void STEPattribute::String( SDAI_String * str ) {
945     assert( NonRefType() == STRING_TYPE );
946     if( ptr.S ) {
947         *( ptr.S ) = * str;
948     } else {
949         ptr.S = str;
950     }
951 }
952 
Binary(SDAI_Binary * bin)953 void STEPattribute::Binary( SDAI_Binary * bin ) {
954     assert( NonRefType() == BINARY_TYPE );
955     if( ptr.b ) {
956         *( ptr.b ) = * bin;
957     } else {
958         ptr.b = bin;
959     }
960 }
961 
Entity(SDAI_Application_instance * ent)962 void STEPattribute::Entity( SDAI_Application_instance * ent ) {
963     assert( NonRefType() == ENTITY_TYPE );
964     if( ptr.c ) {
965         delete ptr.c;
966     }
967     ptr.c = new (SDAI_Application_instance * );
968     *( ptr.c ) = ent;
969 }
970 
Aggregate(STEPaggregate * aggr)971 void STEPattribute::Aggregate( STEPaggregate * aggr ) {
972     assert( ( NonRefType() == AGGREGATE_TYPE ) || ( NonRefType() == ARRAY_TYPE ) || ( NonRefType() == BAG_TYPE )
973     || ( NonRefType() == SET_TYPE ) || ( NonRefType() == LIST_TYPE ) );
974     if( ptr.a ) {
975         *( ptr.a ) = * aggr;
976     } else {
977         ptr.a = aggr;
978     }
979 }
980 
Enum(SDAI_Enum * enu)981 void STEPattribute::Enum( SDAI_Enum * enu ) {
982     assert( NonRefType() == ENUM_TYPE );
983     if( ptr.e ) {
984         ptr.e->set_null();
985         *( ptr.e ) = * enu;
986     } else {
987         ptr.e = enu;
988     }
989 }
990 
Logical(SDAI_LOGICAL * log)991 void STEPattribute::Logical( SDAI_LOGICAL * log ) {
992     assert( NonRefType() == LOGICAL_TYPE );
993     if( ptr.e ) {
994         ptr.e->set_null();
995         *( ptr.e ) = * log;
996     } else {
997         ptr.e = log;
998     }
999 }
1000 
Boolean(SDAI_BOOLEAN * boo)1001 void STEPattribute::Boolean( SDAI_BOOLEAN * boo ) {
1002     assert( NonRefType() == BOOLEAN_TYPE );
1003     if( ptr.e ) {
1004         ptr.e->set_null();
1005         *( ptr.e ) = *boo;
1006     } else {
1007         ptr.e = boo;
1008     }
1009 }
1010 
Select(SDAI_Select * sel)1011 void STEPattribute::Select( SDAI_Select * sel ) {
1012     assert( NonRefType() == SELECT_TYPE );
1013     if( ptr.sh ) {
1014         ptr.sh->set_null();
1015         *( ptr.sh ) = * sel;
1016     } else {
1017         ptr.sh = sel;
1018     }
1019 }
1020 
Undefined(SCLundefined * undef)1021 void STEPattribute::Undefined( SCLundefined * undef ) {
1022     //FIXME is this right, or is the Undefined() above right?
1023     assert( NonRefType() == REFERENCE_TYPE || NonRefType() == UNKNOWN_TYPE );
1024     if( ptr.u ) {
1025         *( ptr.u ) = * undef;
1026     } else {
1027         ptr.u = undef;
1028     }
1029 }
1030 
1031 
1032 /** evaluate the equality of two attributes
1033  * ignores _error and refCount, since those are ancillary
1034  *  \return true if equal
1035  */
operator ==(const STEPattribute & a1,const STEPattribute & a2)1036 bool operator == ( const STEPattribute & a1, const STEPattribute & a2 ) {
1037     if( & a1 == & a2 ) {
1038         return true;
1039     }
1040     if( a1._derive == a2._derive && a1.aDesc == a2.aDesc && a1._redefAttr == a2._redefAttr ){
1041         if( 0 == memcmp( & a1.ptr, & a2.ptr, sizeof( a1.ptr ) ) ) {
1042             return true;
1043         } else {
1044             //ptr differs between a1 and a2, but contents aren't necessarily different
1045             return a1.asStr() == a2.asStr();
1046         }
1047     }
1048     return false;
1049 }
1050 
1051 /** evaluate the equality of two attributes
1052  * ignores _error and refCount, since those are ancillary
1053  *  \return true if not equal
1054  */
operator !=(const STEPattribute & a1,const STEPattribute & a2)1055 bool operator != ( const STEPattribute & a1, const STEPattribute & a2 ) {
1056   return !( a1 == a2 );
1057 }
1058 
1059 /// return true if the attr descriptor is identical
sameADesc(const STEPattribute & a1,const STEPattribute & a2)1060 bool sameADesc( const STEPattribute & a1, const STEPattribute & a2 ) {
1061     return a1.aDesc == a2.aDesc;
1062 }
1063 
1064 
1065 
1066 /**************************************************************//**
1067  * \returns the severity level that the parameter attrValue would pass if it
1068  * was the value for this attribute.
1069  * *note* for string values - (attrValue = 0) => string value does not exist,
1070  *       attrValue exists it is valid.
1071 ******************************************************************/
ValidLevel(const char * attrValue,ErrorDescriptor * error,InstMgrBase * im,bool clearError)1072 Severity STEPattribute::ValidLevel( const char * attrValue, ErrorDescriptor * error, InstMgrBase * im, bool clearError ) {
1073     if( clearError ) {
1074         ClearErrorMsg();
1075     }
1076 
1077     if( _redefAttr )  {
1078         return _redefAttr->ValidLevel( attrValue, error, im, clearError );
1079     }
1080     bool optional = Nullable();
1081 
1082     if( !attrValue ) {
1083         if( optional ) {
1084             return error->severity();
1085         } else {
1086             error->GreaterSeverity( SEVERITY_INCOMPLETE );
1087             return SEVERITY_INCOMPLETE;
1088         }
1089     }
1090     if( attrValue[0] == '\0' ) {
1091         if( NonRefType() == STRING_TYPE ) {
1092             // this is interpreted as a string with no value i.e. "".
1093             // Thus if it exists it has to be valid.
1094             return SEVERITY_NULL;
1095         }
1096         if( optional ) {
1097             return error->severity();
1098         } else {
1099             error->GreaterSeverity( SEVERITY_INCOMPLETE );
1100             return SEVERITY_INCOMPLETE;
1101         }
1102     }
1103 
1104     //  an overridden attribute always has a \'*\' value
1105     if( IsDerived() )  {
1106         if( !strcmp( attrValue, "*" ) ) {
1107             return SEVERITY_NULL;
1108         } else {
1109             _error.AppendToDetailMsg( "attr is derived - value not permitted\n" );
1110             return _error.severity( SEVERITY_INPUT_ERROR );
1111         }
1112     }
1113 
1114     switch( NonRefType() ) {
1115         case INTEGER_TYPE:
1116             return IntValidLevel( attrValue, error, clearError, optional, 0 );
1117 
1118         case STRING_TYPE:
1119             // if a value exists (checked above) then that is the string value
1120             return SEVERITY_NULL;
1121 
1122         case REAL_TYPE:
1123             return RealValidLevel( attrValue, error, clearError, optional, 0 );
1124 
1125         case NUMBER_TYPE:
1126             return NumberValidLevel( attrValue, error, clearError, optional, 0 );
1127 
1128         case ENTITY_TYPE:
1129             return EntityValidLevel( attrValue,
1130                                      aDesc->NonRefTypeDescriptor(),
1131                                      error, im, 0 );
1132         case BINARY_TYPE:
1133             return ptr.b->BinaryValidLevel( attrValue, &_error, optional, 0 );
1134 
1135         case AGGREGATE_TYPE:
1136         case ARRAY_TYPE:      // DAS
1137         case BAG_TYPE:        // DAS
1138         case SET_TYPE:        // DAS
1139         case LIST_TYPE: {     // DAS
1140             return ptr.a->AggrValidLevel( attrValue, error,
1141                                           aDesc->AggrElemTypeDescriptor(), im,
1142                                           optional, 0, 0, 0 );
1143         }
1144         case ENUM_TYPE:
1145         case BOOLEAN_TYPE:
1146         case LOGICAL_TYPE:
1147             return ptr.e->EnumValidLevel( attrValue, error, optional, 0, 0, 1 );
1148         case SELECT_TYPE:
1149             return ptr.sh->SelectValidLevel( attrValue, error, im );
1150 
1151         default:
1152             cerr << "Internal error:  " << __FILE__ <<  __LINE__
1153                  << "\n" << _POC_ "\n";
1154             return error->severity();
1155     }
1156 }
1157 
1158 /**************************************************************//**
1159 ** \param out -- output stream
1160 ** \param a -- attribute to output
1161 ** Description:  overloads the output operator to print an attribute
1162 ******************************************************************/
operator <<(ostream & out,STEPattribute & a)1163 ostream & operator<< ( ostream & out, STEPattribute & a ) {
1164     a.STEPwrite( out );
1165     return out;
1166 }
1167 
1168 /**************************************************************//**
1169 * This prepends attribute information to the detailed error msg.  This
1170 * is intended to add information to the error msgs written by Enumerations,
1171 * Aggregates, and SDAI_Strings which don't know they are a STEPattribute
1172 * value.
1173 ******************************************************************/
AddErrorInfo()1174 void STEPattribute::AddErrorInfo() {
1175     char errStr[BUFSIZ];
1176     errStr[0] = '\0';
1177     if( SEVERITY_INPUT_ERROR < _error.severity() &&
1178             _error.severity() < SEVERITY_NULL ) {
1179         sprintf( errStr, " Warning: ATTRIBUTE '%s : %s : %d' - ",
1180                  Name(), TypeName(), Type() );
1181         _error.PrependToDetailMsg( errStr );
1182     } else if( _error.severity() == SEVERITY_INPUT_ERROR ) {
1183         sprintf( errStr, " Error: ATTRIBUTE '%s : %s : %d' - ",
1184                  Name(), TypeName(), Type() );
1185         _error.PrependToDetailMsg( errStr );
1186     } else if( _error.severity() <= SEVERITY_BUG ) {
1187         sprintf( errStr, " BUG: ATTRIBUTE '%s : %s : %d' - ",
1188                  Name(), TypeName(), Type() );
1189         _error.PrependToDetailMsg( errStr );
1190     }
1191 }
1192 
1193 /**************************************************************//**
1194 * this function reads until it hits eof or one of the StopChars.
1195 * if it hits one of StopChars it puts it back.
1196 * RETURNS: the last char it read.
1197 ******************************************************************/
SkipBadAttr(istream & in,char * StopChars)1198 char STEPattribute::SkipBadAttr( istream & in, char * StopChars ) {
1199     ios_base::fmtflags flbuf = in.flags();
1200     in.unsetf( ios::skipws ); // turn skipping whitespace off
1201 
1202     // read bad data until end of this attribute or entity.
1203     char * foundCh = 0;
1204     char c = '\0';
1205     char errStr[BUFSIZ];
1206     errStr[0] = '\0';
1207 
1208     _error.GreaterSeverity( SEVERITY_WARNING );
1209     in >> c;
1210     while( !in.eof() && !( foundCh = strchr( StopChars, c ) ) ) {
1211         in >> c;
1212     }
1213     if( in.eof() ) {
1214         _error.GreaterSeverity( SEVERITY_INPUT_ERROR );
1215         sprintf( errStr, " Error: attribute '%s : %s : %d' - %s.\n",
1216                  Name(), TypeName(), Type(),
1217                  "Unexpected EOF when skipping bad attr value" );
1218         _error.AppendToDetailMsg( errStr );
1219     } else {
1220         sprintf( errStr, " Error: attribute '%s : %s : %d' - %s.\n",
1221                  Name(), TypeName(), Type(), "Invalid value" );
1222         _error.AppendToDetailMsg( errStr );
1223     }
1224     in.putback( c );
1225     in.flags( flbuf ); // set skip whitespace to its original state
1226     return c;
1227 }
1228