2074fda7e59b7d37f812ede7a22f80574f8d0bc6
[occt.git] / src / StepData / StepData_StepReaderData.cxx
1 //    abv 09.04.99 S4136: eliminate parameter step.readaccept.void
2 //    sln 04,10.2001. BUC61003. Prevent exception which may occur during reading of complex entity (if entity's items are not in alphabetical order)
3 #include <StepData_StepReaderData.ixx>
4 #include <StepData_StepModel.hxx>
5 #include <Interface_FileParameter.hxx>
6 #include <Interface_ParamList.hxx>
7 #include <Message_Messenger.hxx>
8 #include <Message.hxx>
9 #include <Interface_Static.hxx>
10 #include <Interface_Macros.hxx>
11
12 #include <TColStd_SequenceOfInteger.hxx>
13 #include <TColStd_HArray1OfInteger.hxx>
14 #include <TColStd_Array1OfInteger.hxx>
15 #include <TColStd_IndexedMapOfInteger.hxx>
16 #include <TCollection_HAsciiString.hxx>
17
18 #include <TColStd_HArray1OfTransient.hxx>
19 #include <TColStd_HArray1OfReal.hxx>
20 #include <Interface_HArray1OfHAsciiString.hxx>
21 #include <StepData_SelectMember.hxx>
22 #include <StepData_SelectNamed.hxx>
23 #include <StepData_SelectReal.hxx>
24 #include <StepData_SelectInt.hxx>
25 #include <TColStd_HSequenceOfReal.hxx>
26 #include <StepData_SelectArrReal.hxx>
27
28 #include <stdio.h>
29
30
31 // Le Header est constitue d entites analogues dans leur principe a celles
32 // du Data, a ceci pres qu elles sont sans identifieur, et ne peuvent ni
33 // referencer, ni etre referencees (que ce soit avec Header ou avec Data)
34 // Ainsi, dans StepReaderData, le Header est constitue des "thenbhead" 1res Entites
35
36
37 //  #########################################################################
38 //  ....   Creation et Acces de base aux donnees atomiques du fichier    ....
39
40 typedef TCollection_HAsciiString String;
41 typedef Handle(TCollection_HAsciiString) Handle(String);
42 static char txtmes[200];  // plus commode que redeclarer partout
43
44
45 static Standard_Boolean initstr = Standard_False;
46
47 #define Maxlst 64
48 //static TCollection_AsciiString subl[Maxlst];          // Maxlst : minimum 10
49
50 static Standard_Integer acceptvoid = 0;
51
52 // ----------  Fonctions Utilitaires  ----------
53
54 //=======================================================================
55 //function : CleanText
56 //purpose  : 
57 //=======================================================================
58 static void CleanText (const Handle(TCollection_HAsciiString)& val)
59 {
60   Standard_Integer n = val->Length();    // avant reduction
61   val->Remove(n);
62   val->Remove(1);
63 //  Ne pas oublier de traiter les caracteres speciaux
64   for (Standard_Integer i = n-2; i > 0; i --) {
65     char uncar = val->Value(i);
66     if (uncar == '\n')
67       {      val->Remove(i);      if (i < n-2) uncar = val->Value(i);  }
68     if (uncar == '\'' && i < n-2) {
69       if (val->Value(i+1) == '\'')  {  val->Remove(i+1);    continue;  }
70     }
71     if (uncar == '\\' && i < n-2) {
72       if (val->Value(i+1) == '\\')  {  val->Remove(i+1);    continue;  }
73     }
74     else if (uncar == '\\' && i < n-3) {
75       if (val->Value(i+2) == '\\') {
76         if (val->Value(i+1) == 'N')
77           {  val->SetValue(i,'\n');    val->Remove(i+1,2);  continue;  }
78         if (val->Value(i+1) == 'T')
79           {  val->SetValue(i,'\t');    val->Remove(i+1,2);  continue;  }
80       }
81     }
82   }
83 }
84
85 //  -------------  METHODES  -------------
86
87 //=======================================================================
88 //function : StepData_StepReaderData
89 //purpose  : 
90 //=======================================================================
91
92 StepData_StepReaderData::StepData_StepReaderData
93   (const Standard_Integer nbheader, const Standard_Integer nbtotal,
94    const Standard_Integer nbpar)
95 : Interface_FileReaderData (nbtotal,nbpar), theidents (1,nbtotal),
96   thetypes (1,nbtotal) //, themults (1,nbtotal)
97 {
98 //  char textnum[10];
99   thenbscop = 0;  thenbents = 0;  thelastn = 0;  thenbhead = nbheader;
100   //themults.Init(0);
101   thecheck = new Interface_Check;
102 //:S4136  acceptvoid = Interface_Static::IVal("step.readaccept.void");
103   if (initstr) return;
104   //for (Standard_Integer i = 0; i < Maxlst; i ++) {
105   //  sprintf(textnum,"$%d",i+1);
106   //  subl[i].AssignCat(textnum);
107   //}
108   initstr = Standard_True;
109 }
110
111
112 //=======================================================================
113 //function : SetRecord
114 //purpose  : 
115 //=======================================================================
116
117 void StepData_StepReaderData::SetRecord (const Standard_Integer num,
118                                          const Standard_CString ident,
119                                          const Standard_CString type,
120                                          const Standard_Integer /* nbpar */)
121 {
122   Standard_Integer numlst;
123 /*
124   if (strcmp(type,"/ * (SUB) * /") == 0) {    // defini dans recfile.pc
125     thetypes.SetValue (num,sublist);
126   } else {
127     thenbents ++;   // total de termes propres du fichier
128     thetypes.SetValue(num,TCollection_AsciiString(type));
129 //    if (strcmp(ident,"SCOPE") != 0) thenbscop ++;  // ?? a verifier
130   }
131 */
132   if (type[0] != '(') thenbents ++;   // total de termes propres du fichier
133   
134   //thetypes.ChangeValue(num).SetValue(1,type); gka memory
135   //============================================
136   Standard_Integer index = 0;
137   TCollection_AsciiString strtype(type);
138   if(thenametypes.Contains(type))
139     index = thenametypes.FindIndex(strtype);
140   else index = thenametypes.Add(strtype);
141   thetypes.ChangeValue(num) = index;
142   //===========================================
143     
144   if (ident[0] == '$') {
145     if (strlen(ident) > 2) numlst = atoi(&ident[1]);
146     else numlst = ident[1] - 48;
147     if (thelastn < numlst) thelastn = numlst;    // plus fort n0 de sous-liste
148     theidents.SetValue(num,-2-numlst);
149   } else if (ident[0] == '#') {
150     numlst = atoi(&ident[1]);
151     theidents.SetValue(num,numlst);
152     if (numlst == 0 && num > thenbhead) {
153 //    Header, ou bien Type Complexe ...
154 //    Si Type Complexe, retrouver Type Precedent (on considere que c est rare)
155 //    On chaine le type precedent sur le suivant
156 //    VERIFICATION que les types sont en ordre alphabetique
157       for (Standard_Integer prev = num-1; prev > thenbhead; prev --) {
158         if (theidents(prev) >= 0) {
159
160           //themults.SetValue(prev,num);
161           themults.Bind(prev,num);
162           if(thenametypes.FindKey(thetypes.Value(num)).IsLess(thenametypes.FindKey(thetypes.Value(prev)))) {
163           //if (thetypes.Value(num).IsLess(thetypes.Value(prev))) 
164
165 //  ERREUR : Type complexe pas en ordre alphabetique. On enregistre.
166             TCollection_AsciiString errm("Complex Type incorrect : ");
167             errm.AssignCat(thenametypes.FindKey(thetypes.Value(prev)));
168             errm.AssignCat(" / ");
169             errm.AssignCat(thenametypes.FindKey(thetypes.Value(num)));
170             errm.AssignCat(" ... ");
171             thecheck->AddFail(errm.ToCString(),"Complex Type incorrect : ");
172 //  On Affiche a l ecran, le plus de donnees possibles
173             while (theidents(prev) <= 0) {
174               prev --;  if (prev <= 0) break;
175             }
176             Handle(Message_Messenger) sout = Message::DefaultMessenger();
177             sout << "  ***  Error on Record " << num << " (on " << NbRecords()
178               << " -> " << num*100/NbRecords() << " % in File)  ***";
179             if (prev > 0) sout << "  Ident #" << theidents(prev);
180             sout << "\n" << errm << endl;
181           }
182           break;
183         }
184       }
185     }
186   }
187   else if (!strcmp(ident,"SCOPE")) {
188     theidents.SetValue(num,-1); // SCOPE
189     thenbscop ++;
190   }
191   else if (!strcmp(ident,"ENDSCOPE")) theidents.SetValue(num,-2);  // ENDSCOPE
192 //      Reste 0
193
194  // InitParams(num);
195 }
196
197
198 //=======================================================================
199 //function : AddStepParam
200 //purpose  : 
201 //=======================================================================
202
203 void StepData_StepReaderData::AddStepParam (const Standard_Integer num,
204                                             const Standard_CString aval,
205                                             const Interface_ParamType atype,
206                                             const Standard_Integer nument)
207 {
208   if (atype == Interface_ParamSub) {
209     Standard_Integer numid = 0;
210     if (aval[2] != '\0') {
211       numid = atoi(&aval[1]);
212 //      if (numid <= Maxlst) Interface_FileReaderData::AddParam
213 //      (num,subl[numid-1].ToCString(),atype,numid);
214       Interface_FileReaderData::AddParam (num,aval,atype,numid);
215     } else {
216       char *numlstchar = (char *)(aval+1);
217       numid = (*numlstchar) - 48;  // -48 ('0') -1 (adresse [] depuis 0)
218 //      Interface_FileReaderData::AddParam (num,subl[numid].ToCString(),atype,numid);
219       Interface_FileReaderData::AddParam (num,aval,atype,numid);
220     }
221   } else if (atype == Interface_ParamIdent) {
222     Standard_Integer numid = atoi(&aval[1]);
223     Interface_FileReaderData::AddParam (num,aval,atype,numid);
224   } else {
225     Interface_FileReaderData::AddParam (num,aval,atype,nument);
226   }
227
228 //  Interface_FileReaderData::AddParam (num,parval,atype,numid);
229 }
230
231
232 //=======================================================================
233 //function : RecordType
234 //purpose  : 
235 //=======================================================================
236
237 const TCollection_AsciiString& StepData_StepReaderData::RecordType
238   (const Standard_Integer num) const
239 {
240   return thenametypes.FindKey(thetypes.Value(num));  
241 }
242
243
244 //=======================================================================
245 //function : CType
246 //purpose  : 
247 //=======================================================================
248
249 Standard_CString StepData_StepReaderData::CType(const Standard_Integer num) const
250 {
251   return thenametypes.FindKey(thetypes.Value(num)).ToCString();
252 }
253
254
255 //=======================================================================
256 //function : RecordIdent
257 //purpose  : 
258 //=======================================================================
259
260 Standard_Integer StepData_StepReaderData::RecordIdent (const Standard_Integer num) const
261 {
262   return theidents(num);
263 }
264
265
266 //  ########################################################################
267 //  ....       Aides a la lecture des parametres, adaptees a STEP       ....
268
269
270 //=======================================================================
271 //function : SubListNumber
272 //purpose  : 
273 //=======================================================================
274
275 Standard_Integer StepData_StepReaderData::SubListNumber (const Standard_Integer num,
276                                                          const Standard_Integer nump,
277                                                          const Standard_Boolean aslast) const
278 {
279   if (nump == 0 || nump > NbParams(num)) return 0;
280   const Interface_FileParameter& FP = Param(num,nump);
281   if (FP.ParamType() != Interface_ParamSub) return 0;
282   if (aslast)  {  if(nump != NbParams(num)) return 0;  }
283   return FP.EntityNumber();
284 }
285
286
287 //=======================================================================
288 //function : IsComplex
289 //purpose  : 
290 //=======================================================================
291
292 Standard_Boolean StepData_StepReaderData::IsComplex(const Standard_Integer num) const
293 {
294   //return (themults(num) != 0);
295   return themults.IsBound(num);
296 }
297
298
299 //=======================================================================
300 //function : ComplexType
301 //purpose  : 
302 //=======================================================================
303
304 void  StepData_StepReaderData::ComplexType(const Standard_Integer num,
305                                            TColStd_SequenceOfAsciiString& types) const
306 {
307   if (theidents(num) < 0) return;
308   for (Standard_Integer i = num; i > 0; i = NextForComplex(i)) {
309     types.Append(RecordType(i));
310   }
311 }
312
313
314 //=======================================================================
315 //function : NextForComplex
316 //purpose  : 
317 //=======================================================================
318
319 Standard_Integer StepData_StepReaderData::NextForComplex
320   (const Standard_Integer num) const
321 {
322   Standard_Integer next =0;
323   if(themults.IsBound(num))
324     next = themults.Find(num);
325   return next;
326 }
327
328
329 //=======================================================================
330 //function : stepstrcmp
331 //purpose  : 
332 //=======================================================================
333 static Standard_Boolean stepstrcmp(const Standard_CString type,
334                                    const Standard_CString name)
335 {
336 //  name peut etre d un tenant ou de deux : auquel cas il a une partie LONGUE
337 //  et une partie COURTE separees par un blanc
338 //  Attention : False pour dire OK, True sinon (car remplace strcmp)
339   Standard_Integer i,j = 0; Standard_Boolean res = Standard_False;
340   for (i = 0; name[i] != '\0' && type[i] != '\0' && !res ; i ++) {
341     if (name[i] == ' ') { j = i; break; }
342     if (type[i] != name[i]) res = Standard_True;
343   }
344   if (!res || (j == 0)) return res;
345 //  Pas trouve et un blanc suit : on continue
346   for (i = j+1; name[i] != '\0'; i ++) {
347     if (type[i-j-1] != name[i]) return Standard_True;
348   }
349   return Standard_False;
350 }
351
352
353 //=======================================================================
354 //function : NamedForComplex
355 //purpose  : 
356 //=======================================================================
357
358 Standard_Boolean  StepData_StepReaderData::NamedForComplex
359   (const Standard_CString name, const Standard_Integer num0,
360    Standard_Integer& num, Handle(Interface_Check)& ach) const
361 {
362   //Standard_Boolean stat = Standard_True;
363   Standard_Integer n = (num <= 0 ? num0 : NextForComplex(num));
364   // sln 04,10.2001. BUC61003. if(n==0) the next  function is not called in order to avoid exception
365   if ((n!=0) && (!stepstrcmp (RecordType(n).ToCString(),name)))
366     {  num = n;  return Standard_True;  }
367   
368   if (n == 0) /*stat =*/ NamedForComplex (name,num0,n,ach);  // on a rembobine
369 //  Pas dans l ordre alphabetique : boucler
370   Handle(String) errmess = new String("Parameter n0.%d (%s) not a LIST");
371   sprintf (txtmes,errmess->ToCString(),num0,name);
372   for (n = num0; n > 0; n = NextForComplex(n)) {
373     if (!stepstrcmp (RecordType(n).ToCString(),name))  {
374       num = n;
375       errmess = new String("Complex Record n0.%d, member type %s not in alphabetic order");
376       sprintf (txtmes,errmess->ToCString(),num0,name);
377       ach->AddWarning(txtmes,errmess->ToCString());
378       return Standard_False;
379     }
380   }
381   num = 0;
382   errmess = new String("Complex Record n0.%d, member type %s not found");
383   sprintf (txtmes,errmess->ToCString(),num0,name);
384   ach->AddFail (txtmes,errmess->ToCString());
385   return Standard_False;
386 }
387
388 //  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##
389
390
391 //=======================================================================
392 //function : CheckNbParams
393 //purpose  : 
394 //=======================================================================
395
396 Standard_Boolean StepData_StepReaderData::CheckNbParams(const Standard_Integer num,
397                                                         const Standard_Integer nbreq,
398                                                         Handle(Interface_Check)& ach,
399                                                         const Standard_CString mess) const
400 {
401   if (NbParams(num) == nbreq) return Standard_True;
402   Handle(String) errmess;
403   if (mess[0] == '\0') errmess = new String("Count of Parameters is not %d");
404   else errmess = new String("Count of Parameters is not %d for %s");
405   sprintf (txtmes,errmess->ToCString(),nbreq,mess);
406   ach->AddFail (txtmes,errmess->ToCString());
407   return Standard_False;
408 }
409
410
411 //=======================================================================
412 //function : ReadSubList
413 //purpose  : 
414 //=======================================================================
415
416 Standard_Boolean StepData_StepReaderData::ReadSubList(const Standard_Integer num,
417                                                       const Standard_Integer nump,
418                                                       const Standard_CString mess,
419                                                       Handle(Interface_Check)& ach,
420                                                       Standard_Integer& numsub,
421                                                       const Standard_Boolean optional,
422                                                       const Standard_Integer /* lenmin */,
423                                                       const Standard_Integer /* lenmax */) const
424 {
425   numsub = SubListNumber (num,nump,Standard_False);
426   if (numsub > 0) return Standard_True;
427 //  Si optionel indefini, on passe l eponge
428   numsub = 0;
429   Standard_Boolean isvoid = (Param(num,nump).ParamType() == Interface_ParamVoid);
430   if (isvoid && optional) return Standard_False;
431
432   Handle(String) errmess = new String("Parameter n0.%d (%s) not a LIST");
433   sprintf (txtmes,errmess->ToCString(),nump,mess);
434   if (acceptvoid && isvoid)  ach->AddWarning(txtmes,errmess->ToCString());
435   else  {  ach->AddFail(txtmes,errmess->ToCString()); return Standard_False;  }
436   return Standard_True;
437 }
438
439
440 //  ...   Facilites pour LateBinding
441
442
443 //=======================================================================
444 //function : ReadSub
445 //purpose  : 
446 //=======================================================================
447
448 Standard_Integer StepData_StepReaderData::ReadSub(const Standard_Integer numsub,
449                                                   const Standard_CString mess,
450                                                   Handle(Interface_Check)& ach,
451                                                   const Handle(StepData_PDescr)& descr,
452                                                   Handle(Standard_Transient)& val) const
453 {
454   Standard_Integer nbp = NbParams(numsub);
455   if (nbp == 0) return 0;    // liste vide = Handle Null
456   const TCollection_AsciiString& rectyp = RecordType (numsub);
457   if (nbp == 1 && rectyp.ToCString()[0] != '(') {
458     //  c est un type avec un parametre -> SelectNamed
459     //  cf ReadSelect mais ici, on est deja sur le contenu du parametre
460     Handle(StepData_SelectNamed) sn = new StepData_SelectNamed;
461     val = sn;
462     sn->SetName (rectyp.ToCString());
463     if (ReadAny (numsub,1,mess,ach,descr,sn)) return sn->Kind();
464     else return 0;
465   }
466
467   //  cas courant : faire un HArray1 de ... de ... de quoi au fait
468   const Interface_FileParameter& FP0 = Param(numsub,1);
469   Interface_ParamType FT, FT0 = FP0.ParamType();
470   Standard_CString str = FP0.CValue();
471   Handle(TColStd_HArray1OfTransient) htr;
472   Handle(TColStd_HArray1OfInteger)   hin;
473   Handle(TColStd_HArray1OfReal)      hre;
474   Handle(Interface_HArray1OfHAsciiString)  hst;
475   Standard_Integer kod = 0;
476   switch (FT0) {
477     case Interface_ParamMisc    : return -1;
478     case Interface_ParamInteger : kod = 1;  break;
479     case Interface_ParamReal    : kod = 5;  break;
480     case Interface_ParamIdent   : kod = 7;  break;
481     case Interface_ParamVoid    : kod = 0;  break;
482     case Interface_ParamText    : kod = 6;  break;
483     case Interface_ParamEnum    : kod = 4;  break;  // a confirmer(logical)
484       /*      kod = 4;
485               if ( str[0] == '.' && str[2] == '.' && str[3] == '\0' &&
486               (str[1] == 'T' || str[1] == 'F' || str[1] == 'U') ) kod = 3;
487               break; */ // svv #2
488     case Interface_ParamLogical : return -1;
489     case Interface_ParamSub     : kod = 0;  break;
490     case Interface_ParamHexa    : return -1;
491     case Interface_ParamBinary  : return -1;
492     default :  return -1;
493   }
494   if (kod == 1 || kod == 3) { hin = new TColStd_HArray1OfInteger (1,nbp); val = hin; }
495   else if (kod == 5) { hre = new TColStd_HArray1OfReal   (1,nbp); val = hre; }
496   else if (kod == 6) { hst = new Interface_HArray1OfHAsciiString (1,nbp); val = hst; }
497   else            { htr = new TColStd_HArray1OfTransient (1,nbp); val = htr; }
498 //  Attention : si type variable, faudra changer son fusil d epaule -> htr
499
500   for (Standard_Integer ip = 1; ip <= nbp; ip ++) {
501     const Interface_FileParameter& FP = Param(numsub,ip);
502     str = FP.CValue();
503     FT  = FP.ParamType();
504     switch (kod) {
505       case 1 : {
506         if (FT != Interface_ParamInteger) { kod = 0; break; }
507         hin->SetValue (ip,atoi(str));   break;
508       }
509       case 2 :
510       case 3 : {
511         if (FT != Interface_ParamEnum)    { kod = 0; break; }
512         if      (!strcmp(str,".F.")) hin->SetValue (ip,0);
513         else if (!strcmp(str,".T.")) hin->SetValue (ip,1);
514         else if (!strcmp(str,".U.")) hin->SetValue (ip,2);
515         else    kod = 0;
516         break;
517       }
518       case 4 : {
519         if (FT != Interface_ParamEnum)    { kod = 0; break; }
520         Handle(StepData_SelectNamed) sn = new StepData_SelectNamed;
521         sn->SetEnum (-1,str);
522         htr->SetValue (ip,sn);  break;
523       }
524       case 5 : {
525         if (FT != Interface_ParamReal)    { kod = 0; break; }
526         hre->SetValue (ip,Interface_FileReaderData::Fastof(str));   break;
527       }
528       case 6 : {
529         if (FT != Interface_ParamText)    { kod = 0; break; }
530         Handle(TCollection_HAsciiString) txt = new TCollection_HAsciiString(str);
531         CleanText (txt);  hst->SetValue (ip,txt);  break;
532       }
533       case 7 : {
534         Handle(Standard_Transient) ent = BoundEntity (FP.EntityNumber());
535         htr->SetValue (ip,ent);  break;
536       }
537       default : break;
538     }
539 //    Restent les autres cas ... tout est possible. cf le type du Param
540     if (kod > 0) continue;
541 //    Il faut passer au transient ...
542     if (htr.IsNull()) {
543       htr = new TColStd_HArray1OfTransient (1,nbp);  val = htr;
544       Standard_Integer jp;      
545       if (!hin.IsNull()) {
546         for (jp = 1; jp < ip; jp ++) {
547           Handle(StepData_SelectInt) sin = new StepData_SelectInt;
548           sin->SetInt (hin->Value(jp));
549           htr->SetValue (jp,sin);
550         }
551       }
552       if (!hre.IsNull()) {
553         for (jp = 1; jp < ip; jp ++) {
554           Handle(StepData_SelectReal) sre = new StepData_SelectReal;
555           sre->SetReal (hre->Value(jp));
556           htr->SetValue (jp,sre);
557         }
558       }
559       if (!hst.IsNull()) {
560         for (jp = 1; jp < ip; jp ++) {
561           htr->SetValue (jp,hst->Value(jp));
562         }
563       }
564     }
565 //    A present, faut y aller : lire le champ et le mettre en place
566 //    Ce qui suit ressemble fortement a ReadAny ...
567
568     switch (FT) {
569     case Interface_ParamMisc : break;
570     case Interface_ParamInteger : {
571       Handle(StepData_SelectInt) sin = new StepData_SelectInt;
572       sin->SetInteger (atoi(str));
573       htr->SetValue (ip,sin); break;
574     }
575     case Interface_ParamReal : {
576       Handle(StepData_SelectReal) sre = new StepData_SelectReal;
577       sre->SetReal (Interface_FileReaderData::Fastof(str));   break;
578       //htr->SetValue (ip,sre); break; svv #2: unreachable
579     }
580     case Interface_ParamIdent : htr->SetValue (ip,BoundEntity (FP.EntityNumber()));  break;
581     case Interface_ParamVoid : break;
582     case Interface_ParamEnum : {
583       Handle(StepData_SelectInt)   sin;
584       Handle(StepData_SelectNamed) sna;
585       Standard_Integer logic = -1;
586 // PTV 16.09.2000
587 // set the default value of StepData_Logical
588       StepData_Logical slog = StepData_LUnknown;
589       if ( str[0] == '.' && str[2] == '.' && str[3] == '\0') {
590         if (str[1] == 'F')       {  slog = StepData_LFalse;    logic = 0;  }
591         else if (str[1] == 'T')  {  slog = StepData_LTrue;     logic = 1;  }
592         else if (str[1] == 'U')  {  slog = StepData_LUnknown;  logic = 2;  }
593       }
594       if (logic >= 0)
595         { sin = new StepData_SelectInt; sin->SetLogical(slog); htr->SetValue(ip,sin); }
596       else { sna = new StepData_SelectNamed;
597              sna->SetEnum (logic,str); htr->SetValue (ip,sna);  }
598       break;
599     }
600     case Interface_ParamLogical : break;
601     case Interface_ParamText : {
602       Handle(TCollection_HAsciiString) txt = new TCollection_HAsciiString(str);
603       CleanText (txt);  htr->SetValue (ip,txt);  break;
604     }
605     case Interface_ParamSub  : {
606       Handle(Standard_Transient) sub;
607       Standard_Integer nent = FP.EntityNumber();
608       Standard_Integer kind = ReadSub (nent,mess,ach,descr,sub);   if (kind < 0) break;
609       htr->SetValue(ip,sub);  break;
610     }
611     case Interface_ParamHexa : break;
612     case Interface_ParamBinary  : break;
613     default                  : break;
614     }
615     return -1;
616   }
617   return 8;  // pour Any
618 }
619
620
621 //=======================================================================
622 //function : ReadMember
623 //purpose  : 
624 //=======================================================================
625
626 Standard_Boolean StepData_StepReaderData::ReadMember(const Standard_Integer num,
627                                                      const Standard_Integer nump,
628                                                      const Standard_CString mess,
629                                                      Handle(Interface_Check)& ach,
630                                                      Handle(StepData_SelectMember)& val) const
631 {
632   Handle(Standard_Transient) v = val;
633   Handle(StepData_PDescr) nuldescr;
634   if (v.IsNull()) return ReadAny (num,nump,mess,ach,nuldescr,val);
635   Standard_Boolean res = ReadAny (num,nump,mess,ach,nuldescr,v);
636   if (v == val) return res;
637   //   changement -> refus
638   Handle(String) errmess =
639     new String("Parameter n0.%d (%s) : does not match SELECT clause");
640   sprintf (txtmes,errmess->ToCString(),nump,mess);
641   ach->AddFail(txtmes,errmess->ToCString());
642   return Standard_False;
643 }
644
645
646 //=======================================================================
647 //function : ReadField
648 //purpose  : 
649 //=======================================================================
650
651 Standard_Boolean StepData_StepReaderData::ReadField(const Standard_Integer num,
652                                                     const Standard_Integer nump,
653                                                     const Standard_CString mess,
654                                                     Handle(Interface_Check)& ach,
655                                                     const Handle(StepData_PDescr)& descr,
656                                                     StepData_Field& fild) const
657 {
658   const Interface_FileParameter& FP = Param(num,nump);
659   Standard_CString str = FP.CValue();
660   Standard_Boolean OK = Standard_True;
661   Standard_Integer nent, kind;
662   Handle(TCollection_HAsciiString) txt;
663   Handle(Standard_Transient) sub;
664   Interface_ParamType FT = FP.ParamType();
665   switch (FT) {
666     case Interface_ParamMisc    : OK = Standard_False;  break;
667     case Interface_ParamInteger : fild.SetInteger (atoi(str)); break;
668     case Interface_ParamReal    :
669       fild.SetReal (Interface_FileReaderData::Fastof(str));   break;
670     case Interface_ParamIdent   :
671       nent = FP.EntityNumber();
672       if (nent > 0) fild.SetEntity (BoundEntity(nent));
673       break;
674     case Interface_ParamVoid    :  break;
675     case Interface_ParamText    :
676       txt = new TCollection_HAsciiString(str);
677       CleanText (txt);  fild.Set (txt);  break;
678     case Interface_ParamEnum    :
679       if      (!strcmp(str,".T.")) fild.SetLogical (StepData_LTrue);
680       else if (!strcmp(str,".F.")) fild.SetLogical (StepData_LFalse);
681       else if (!strcmp(str,".U.")) fild.SetLogical (StepData_LUnknown);
682       else    fild.SetEnum (-1,str);
683       break;
684     case Interface_ParamLogical : OK = Standard_False;  break;
685     case Interface_ParamSub     :
686       nent = FP.EntityNumber();
687       kind = ReadSub (nent,mess,ach,descr,sub);   if (kind < 0) break;
688       fild.Clear(kind);  fild.Set (sub);      break;
689     case Interface_ParamHexa    : OK = Standard_False;  break;
690     case Interface_ParamBinary  : OK = Standard_False;  break;
691     default :  OK = Standard_False;  break;
692   }
693
694   if (!OK) {
695     if (!strcmp(str,"*")) fild.SetDerived();
696   }
697   return Standard_True;
698 }
699
700
701 //=======================================================================
702 //function : ReadList
703 //purpose  : 
704 //=======================================================================
705
706 Standard_Boolean StepData_StepReaderData::ReadList(const Standard_Integer num,
707                                                    Handle(Interface_Check)& ach,
708                                                    const Handle(StepData_ESDescr)& descr,
709                                                    StepData_FieldList& list) const
710 {
711   // controler nbs egaux
712   Standard_Integer i,nb = list.NbFields();
713   if (!CheckNbParams (num,nb,ach,descr->TypeName())) return Standard_False;
714   for (i = 1; i <= nb; i ++) {
715     Handle(StepData_PDescr) pde = descr->Field(i);
716     StepData_Field& fild = list.CField(i);
717     ReadField (num,i,pde->Name(),ach,pde,fild);
718   }
719   return Standard_True;
720 }
721
722
723 //=======================================================================
724 //function : ReadAny
725 //purpose  : 
726 //=======================================================================
727
728 Standard_Boolean StepData_StepReaderData::ReadAny(const Standard_Integer num,
729                                                   const Standard_Integer nump,
730                                                   const Standard_CString mess,
731                                                   Handle(Interface_Check)& ach,
732                                                   const Handle(StepData_PDescr)& descr,
733                                                   Handle(Standard_Transient)& val) const
734 {
735   const Interface_FileParameter& FP = Param(num,nump);
736   Standard_CString    str = FP.CValue();
737   Interface_ParamType FT  = FP.ParamType();
738
739 //    A present, faut y aller : lire le champ et le mettre en place
740   switch (FT) {
741     case Interface_ParamMisc : break;
742     case Interface_ParamInteger : {
743       if (!val.IsNull()) {
744         DeclareAndCast(StepData_SelectMember,sm,val);
745         sm->SetInteger(atoi(str));
746         return Standard_True;
747       }
748       Handle(StepData_SelectInt) sin = new StepData_SelectInt;
749       sin->SetInteger (atoi(str));
750       val = sin;
751       return Standard_True;
752     }
753     case Interface_ParamReal : {
754       if (!val.IsNull()) {
755         DeclareAndCast(StepData_SelectMember,sm,val);
756         sm->SetReal (Interface_FileReaderData::Fastof(str));
757         return Standard_True;
758       }
759       Handle(StepData_SelectReal) sre = new StepData_SelectReal;
760       sre->SetReal (Interface_FileReaderData::Fastof(str));
761       val = sre;
762       return Standard_True;
763     }
764     case Interface_ParamIdent   : {
765       Standard_Integer nent = FP.EntityNumber();
766       if (nent > 0) val = BoundEntity(nent);
767       return (!val.IsNull());
768     }
769     case Interface_ParamVoid  : break;
770     case Interface_ParamEnum : {
771       Handle(StepData_SelectMember) sm;
772       if (!val.IsNull())  sm = GetCasted(StepData_SelectMember,val);
773       Handle(StepData_SelectInt)   sin;
774       Handle(StepData_SelectNamed) sna;
775       Standard_Integer logic = -1;
776
777       // PTV 16.09.2000
778       // set the default value of StepData_Logical
779       StepData_Logical slog = StepData_LUnknown;
780       if ( str[0] == '.' && str[2] == '.' && str[3] == '\0') {
781         if (str[1] == 'F')       {  slog = StepData_LFalse;    logic = 0;  }
782         else if (str[1] == 'T')  {  slog = StepData_LTrue;     logic = 1;  }
783         else if (str[1] == 'U')  {  slog = StepData_LUnknown;  logic = 2;  }
784       }
785       if (logic >= 0)  {
786         if (!sm.IsNull()) sm->SetLogical(slog);
787         else {
788           sin = new StepData_SelectInt; val = sin;
789           sin->SetLogical(slog);
790         }
791       }
792       else {
793         if (!sm.IsNull()) sm->SetEnum (logic,str);
794         else {
795           sna = new StepData_SelectNamed;  val = sna;  // Named sans nom...
796           sna->SetEnum (logic,str);
797         }
798       }        // -> Select general
799       return Standard_True;
800     }
801     case Interface_ParamLogical : break;
802     case Interface_ParamText : {
803       Handle(TCollection_HAsciiString) txt = new TCollection_HAsciiString(str);
804       CleanText (txt);
805
806       // PDN May 2000: for reading SOURCE_ITEM (external references)
807       if (!val.IsNull()) {
808         DeclareAndCast(StepData_SelectMember,sm,val);
809         sm->SetString (txt->ToCString());
810         return Standard_True;
811       }
812       
813       val = txt;
814       return Standard_True;
815     }
816     case Interface_ParamSub     : {
817       Standard_Integer numsub = SubListNumber (num,nump,Standard_False);
818       Standard_Integer nbp = NbParams(numsub);
819       if (nbp == 0) return Standard_False;    // liste vide = Handle Null
820       const TCollection_AsciiString& rectyp = RecordType (numsub);
821       if (nbp == 1 && rectyp.ToCString()[0] != '(') {
822         //  SelectNamed because Field !!!
823         // skl 15.01.2003 (for members with array of real)
824         DeclareAndCast(StepData_SelectArrReal,sma,val);
825         if(!sma.IsNull()) {
826           Standard_Integer numsub2 = SubListNumber (numsub,1,Standard_False);
827           Standard_Integer nbp2 = NbParams(numsub2);
828           if(nbp2>1) {
829             if( Param(numsub2,1).ParamType() == Interface_ParamReal ) {
830               if (!sma->SetName (rectyp.ToCString())) return Standard_False;
831               Handle(TColStd_HSequenceOfReal) aSeq = new TColStd_HSequenceOfReal;
832               for(Standard_Integer i=1; i<=nbp2; i++) {
833                 if( Param(numsub2,i).ParamType() != Interface_ParamReal ) continue;
834                 Handle(StepData_SelectReal) sm1 = new StepData_SelectReal;
835                 if( !ReadAny(numsub2,i,mess,ach,descr,sm1) ) continue;
836                 aSeq->Append(sm1->Real());
837               }
838               Handle(TColStd_HArray1OfReal) anArr = new TColStd_HArray1OfReal(1,aSeq->Length());
839               for(Standard_Integer nr=1; nr<=aSeq->Length(); nr++) {
840                 anArr->SetValue(nr,aSeq->Value(nr));
841               }
842               sma->SetArrReal(anArr);
843               return Standard_True;
844             }
845           }
846         }
847         DeclareAndCast(StepData_SelectMember,sm,val);
848         if (sm.IsNull()) {
849           sm = new StepData_SelectNamed;
850           val = sm;
851         }
852         if (!sm->SetName (rectyp.ToCString())) return Standard_False;  // loupe
853         return ReadAny (numsub,1,mess,ach,descr,val);
854       }
855     }
856     default                  : break;
857   }
858   return Standard_False;
859 }
860
861
862 //  ....
863
864
865 //=======================================================================
866 //function : ReadXY
867 //purpose  : 
868 //=======================================================================
869
870 Standard_Boolean StepData_StepReaderData::ReadXY(const Standard_Integer num,
871                                                  const Standard_Integer nump,
872                                                  const Standard_CString mess,
873                                                  Handle(Interface_Check)& ach,
874                                                  Standard_Real& X, Standard_Real& Y) const
875 {
876   Handle(String) errmess;  // Null si pas d erreur
877   Standard_Integer numsub = SubListNumber(num,nump,Standard_False);
878   if (numsub != 0) {
879     if (NbParams(numsub) == 2) {
880       const Interface_FileParameter& FPX = Param(numsub,1);
881       if (FPX.ParamType() == Interface_ParamReal)  X =
882         Interface_FileReaderData::Fastof(FPX.CValue());
883       else errmess = new String("Parameter n0.%d (%s) : (X,Y) X not a Real");
884
885       const Interface_FileParameter& FPY = Param(numsub,2);
886       if (FPY.ParamType() == Interface_ParamReal)  Y = 
887         Interface_FileReaderData::Fastof( FPY.CValue());
888       else errmess = new String("Parameter n0.%d (%s) : (X,Y) Y not a Real");
889
890     }
891     else errmess = new String("Parameter n0.%d (%s) : (X,Y) has not 2 params");
892   }
893   else errmess = new String("Parameter n0.%d (%s) : (X,Y) not a SubList");
894
895   if (errmess.IsNull()) return Standard_True;
896   sprintf (txtmes,errmess->ToCString(),nump,mess);
897   ach->AddFail(txtmes,errmess->ToCString());
898   return Standard_False;
899 }
900
901
902 //=======================================================================
903 //function : ReadXYZ
904 //purpose  : 
905 //=======================================================================
906
907 Standard_Boolean StepData_StepReaderData::ReadXYZ(const Standard_Integer num,
908                                                   const Standard_Integer nump,
909                                                   const Standard_CString mess,
910                                                   Handle(Interface_Check)& ach,
911                                                   Standard_Real& X, Standard_Real& Y,
912                                                   Standard_Real& Z) const
913 {
914   Handle(String) errmess;  // Null si pas d erreur
915   Standard_Integer numsub = SubListNumber(num,nump,Standard_False);
916   if (numsub != 0) {
917     if (NbParams(numsub) == 3) {
918       const Interface_FileParameter& FPX = Param(numsub,1);
919       if (FPX.ParamType() == Interface_ParamReal)  X =
920         Interface_FileReaderData::Fastof(FPX.CValue());
921       else errmess = new String("Parameter n0.%d (%s) : (X,Y,Z) X not a Real");
922
923       const Interface_FileParameter& FPY = Param(numsub,2);
924       if (FPY.ParamType() == Interface_ParamReal)  Y =
925         Interface_FileReaderData::Fastof(FPY.CValue());
926       else errmess = new String("Parameter n0.%d (%s) : (X,Y,Z) Y not a Real");
927
928       const Interface_FileParameter& FPZ = Param(numsub,3);
929       if (FPZ.ParamType() == Interface_ParamReal)  Z =
930         Interface_FileReaderData::Fastof(FPZ.CValue());
931       else errmess = new String("Parameter n0.%d (%s) : (X,Y,Z) Z not a Real");
932
933     }
934     else errmess = new String("Parameter n0.%d (%s) : (X,Y,Z) has not 3 params");
935   }
936   else errmess = new String("Parameter n0.%d (%s) : (X,Y,Z) not a SubList");
937
938   if (errmess.IsNull()) return Standard_True;
939   sprintf (txtmes,errmess->ToCString(),nump,mess);
940   ach->AddFail(txtmes,errmess->ToCString());
941   return Standard_False;
942 }
943
944
945 //=======================================================================
946 //function : ReadReal
947 //purpose  : 
948 //=======================================================================
949
950 Standard_Boolean StepData_StepReaderData::ReadReal(const Standard_Integer num,
951                                                    const Standard_Integer nump,
952                                                    const Standard_CString mess,
953                                                    Handle(Interface_Check)& ach,
954                                                    Standard_Real& val) const
955 {
956   Handle(String) errmess;  // Null si pas d erreur
957   if (nump > 0 && nump <= NbParams(num)) {
958     const Interface_FileParameter& FP = Param(num,nump);
959     if (FP.ParamType() == Interface_ParamReal)  val =
960       Interface_FileReaderData::Fastof(FP.CValue());
961     else errmess = new String("Parameter n0.%d (%s) not a Real");
962   }
963   else errmess = new String("Parameter n0.%d (%s) absent");
964
965   if (errmess.IsNull()) return Standard_True;
966   sprintf (txtmes,errmess->ToCString(),nump,mess);
967   ach->AddFail(txtmes,errmess->ToCString());
968   return Standard_False;
969 }
970
971
972 //  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##
973
974
975 //=======================================================================
976 //function : ReadEntity
977 //purpose  : 
978 //=======================================================================
979
980 Standard_Boolean StepData_StepReaderData::ReadEntity(const Standard_Integer num,
981                                                      const Standard_Integer nump,
982                                                      const Standard_CString mess,
983                                                      Handle(Interface_Check)& ach,
984                                                      const Handle(Standard_Type)& atype,
985                                                      Handle(Standard_Transient)& ent) const
986 {
987   Handle(String) errmess;  // Null si pas d erreur
988   Standard_Boolean warn = Standard_False;
989   if (nump > 0 && nump <= NbParams(num)) {
990     const Interface_FileParameter& FP = Param(num,nump);
991     Standard_Integer nent = FP.EntityNumber();
992     if (FP.ParamType() == Interface_ParamIdent) {
993       warn = (acceptvoid > 0);
994       if (nent > 0) {
995         Handle(Standard_Transient) entent = BoundEntity(nent);
996         if (entent.IsNull() || !entent->IsKind(atype))
997           errmess = new String("Parameter n0.%d (%s) : Entity has illegal type");
998         else ent = entent;
999       }
1000       else errmess = new String("Parameter n0.%d (%s) : Unresolved reference");
1001     }
1002     else {
1003       if (acceptvoid && FP.ParamType() == Interface_ParamVoid) warn = Standard_True;
1004       errmess = new String("Parameter n0.%d (%s) not an Entity");
1005     }
1006   }
1007   else {
1008     warn = (acceptvoid > 0);
1009     errmess = new String("Parameter n0.%d (%s) absent");
1010   }
1011
1012   if (errmess.IsNull()) return Standard_True;
1013   sprintf (txtmes,errmess->ToCString(),nump,mess);
1014   if (warn) ach->AddWarning(txtmes,errmess->ToCString());
1015   else ach->AddFail(txtmes,errmess->ToCString());
1016   return Standard_False;
1017 }
1018
1019
1020 //=======================================================================
1021 //function : ReadEntity
1022 //purpose  : 
1023 //=======================================================================
1024
1025 Standard_Boolean StepData_StepReaderData::ReadEntity(const Standard_Integer num,
1026                                                      const Standard_Integer nump,
1027                                                      const Standard_CString mess,
1028                                                      Handle(Interface_Check)& ach,
1029                                                      StepData_SelectType& sel) const
1030 {
1031   Handle(String) errmess;  // Null si pas d erreur
1032   Standard_Boolean warn = Standard_False;
1033   if (nump > 0 && nump <= NbParams(num)) {
1034     const Interface_FileParameter& FP = Param(num,nump);
1035     Standard_Integer nent = FP.EntityNumber();
1036     if (FP.ParamType() == Interface_ParamIdent) {
1037       warn = (acceptvoid > 0);
1038       if (nent > 0) {
1039         Handle(Standard_Transient) entent = BoundEntity(nent);
1040         if (!sel.Matches(entent))
1041           errmess = new String("Parameter n0.%d (%s) : Entity has illegal type");
1042         else
1043           sel.SetValue(entent);
1044       }
1045       else
1046         errmess = new String("Parameter n0.%d (%s) : Unresolved reference");
1047     }
1048     else if (FP.ParamType() == Interface_ParamVoid) {
1049       if (acceptvoid) warn = Standard_True;
1050       errmess = new String("Parameter n0.%d (%s) not an Entity");
1051     }
1052     else {
1053       // Cas restant : on s interesse en fait au SelectMember ...
1054       Handle(Standard_Transient) sm = sel.NewMember();
1055       // SelectMember qui assure ce role. Peut etre specialise
1056       if (!ReadAny (num,nump,mess,ach,sel.Description(),sm))
1057         errmess = new String("Parameter n0.%d (%s) : could not be read");
1058       if (!sel.Matches(sm))
1059         errmess = new String("Parameter n0.%d (%s) : illegal parameter type");
1060       else
1061         sel.SetValue(sm);
1062     }
1063   }
1064   else {
1065     warn = (acceptvoid > 0);
1066     errmess = new String("Parameter n0.%d (%s) absent");
1067   }
1068
1069   if (errmess.IsNull()) return Standard_True;
1070   sprintf (txtmes,errmess->ToCString(),nump,mess);
1071   if (warn) ach->AddWarning(txtmes,errmess->ToCString());
1072   else ach->AddFail(txtmes,errmess->ToCString());
1073   return Standard_False;
1074 }
1075
1076
1077 //  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##
1078
1079
1080 //=======================================================================
1081 //function : ReadInteger
1082 //purpose  : 
1083 //=======================================================================
1084
1085 Standard_Boolean StepData_StepReaderData::ReadInteger(const Standard_Integer num,
1086                                                       const Standard_Integer nump,
1087                                                       const Standard_CString mess,
1088                                                       Handle(Interface_Check)& ach,
1089                                                       Standard_Integer& val) const
1090 {
1091   Handle(String) errmess;  // Null si pas d erreur
1092   if (nump > 0 && nump <= NbParams(num)) {
1093     const Interface_FileParameter& FP = Param(num,nump);
1094     if (FP.ParamType() == Interface_ParamInteger)  val = atoi(FP.CValue());
1095     else errmess = new String("Parameter n0.%d (%s) not an Integer");
1096   }
1097   else errmess = new String("Parameter n0.%d (%s) absent");
1098
1099   if (errmess.IsNull()) return Standard_True;
1100   sprintf (txtmes,errmess->ToCString(),nump,mess);
1101   ach->AddFail(txtmes,errmess->ToCString());
1102   return Standard_False;
1103 }
1104
1105
1106 //=======================================================================
1107 //function : ReadBoolean
1108 //purpose  : 
1109 //=======================================================================
1110
1111 Standard_Boolean StepData_StepReaderData::ReadBoolean(const Standard_Integer num,
1112                                                       const Standard_Integer nump,
1113                                                       const Standard_CString mess,
1114                                                       Handle(Interface_Check)& ach,
1115                                                       Standard_Boolean& flag) const
1116 {
1117   Handle(String) errmess;  // Null si pas d erreur
1118   if (nump > 0 && nump <= NbParams(num)) {
1119     const Interface_FileParameter& FP = Param(num,nump);
1120     if (FP.ParamType() == Interface_ParamEnum) {
1121       Standard_CString txt = FP.CValue();
1122       if      (!strcmp(txt,".T.")) flag = Standard_True;
1123       else if (!strcmp(txt,".F.")) flag = Standard_False;
1124       else errmess = new String("Parameter n0.%d (%s) : Incorrect Boolean Value");
1125     }
1126     else errmess = new String("Parameter n0.%d (%s) not a Boolean");
1127   }
1128   else errmess = new String("Parameter n0.%d (%s) absent");
1129
1130   if (errmess.IsNull()) return Standard_True;
1131   sprintf (txtmes,errmess->ToCString(),nump,mess);
1132   ach->AddFail(txtmes,errmess->ToCString());
1133   return Standard_False;
1134 }
1135
1136
1137 //=======================================================================
1138 //function : ReadLogical
1139 //purpose  : 
1140 //=======================================================================
1141
1142 Standard_Boolean StepData_StepReaderData::ReadLogical(const Standard_Integer num,
1143                                                       const Standard_Integer nump,
1144                                                       const Standard_CString mess,
1145                                                       Handle(Interface_Check)& ach,
1146                                                       StepData_Logical& flag) const
1147 {
1148   Handle(String) errmess;  // Null si pas d erreur
1149   if (nump > 0 && nump <= NbParams(num)) {
1150     const Interface_FileParameter& FP = Param(num,nump);
1151     if (FP.ParamType() == Interface_ParamEnum) {
1152       Standard_CString txt = FP.CValue();
1153       if      (!strcmp(txt,".T.")) flag = StepData_LTrue;
1154       else if (!strcmp(txt,".F.")) flag = StepData_LFalse;
1155       else if (!strcmp(txt,".U.")) flag = StepData_LUnknown;
1156       else errmess = new String("Parameter n0.%d (%s) : Incorrect Logical Value");
1157     }
1158     else errmess = new String("Parameter n0.%d (%s) not a Logical");
1159   }
1160   else errmess = new String("Parameter n0.%d (%s) absent");
1161
1162   if (errmess.IsNull()) return Standard_True;
1163   sprintf (txtmes,errmess->ToCString(),nump,mess);
1164   ach->AddFail(txtmes,errmess->ToCString());
1165   return Standard_False;
1166 }
1167
1168
1169 //=======================================================================
1170 //function : ReadString
1171 //purpose  : 
1172 //=======================================================================
1173
1174 Standard_Boolean StepData_StepReaderData::ReadString(const Standard_Integer num,
1175                                                      const Standard_Integer nump,
1176                                                      const Standard_CString mess,
1177                                                      Handle(Interface_Check)& ach,
1178                                                      Handle(TCollection_HAsciiString)& val) const
1179 {
1180   Handle(String) errmess;  // Null si pas d erreur
1181   Standard_Boolean warn = Standard_False;
1182   if (nump > 0 && nump <= NbParams(num)) {
1183     const Interface_FileParameter& FP = Param(num,nump);
1184     if (FP.ParamType() == Interface_ParamText) {
1185       /*Standard_CString anStr = FP.CValue();
1186       if(strlen(anStr) < 3)
1187         val = new TCollection_HAsciiString("");
1188       else {
1189         val = new TCollection_HAsciiString(FP.CValue());
1190         CleanText (val);
1191       }*/
1192       val = new TCollection_HAsciiString(FP.CValue());
1193       CleanText (val);
1194     } else {
1195       if (acceptvoid && FP.ParamType() == Interface_ParamVoid) warn = Standard_True;
1196       errmess = new String("Parameter n0.%d (%s) not a quoted String");
1197     }
1198   }
1199   else errmess = new String("Parameter n0.%d (%s) absent");
1200
1201   if (errmess.IsNull()) return Standard_True;
1202   sprintf (txtmes,errmess->ToCString(),nump,mess);
1203   if (warn) ach->AddWarning(txtmes,errmess->ToCString());
1204   else ach->AddFail(txtmes,errmess->ToCString());
1205   return Standard_False;
1206 }
1207
1208
1209 //=======================================================================
1210 //function : ReadEnumParam
1211 //purpose  : 
1212 //=======================================================================
1213
1214 Standard_Boolean StepData_StepReaderData::ReadEnumParam(const Standard_Integer num,
1215                                                         const Standard_Integer nump,
1216                                                         const Standard_CString mess,
1217                                                         Handle(Interface_Check)& ach,
1218                                                         Standard_CString& text) const
1219 {
1220   Handle(String) errmess;  // Null si pas d erreur
1221   Standard_Boolean warn = Standard_False;
1222   if (nump > 0 && nump <= NbParams(num)) {
1223     const Interface_FileParameter& FP = Param(num,nump);
1224     if (FP.ParamType() == Interface_ParamEnum) {
1225       text = FP.CValue();
1226       warn = (acceptvoid > 0);
1227     } else if (FP.ParamType() == Interface_ParamVoid) {
1228       errmess =
1229         new String("Parameter n0.%d (%s) : Undefined Enumeration not allowed");
1230       warn = (acceptvoid > 0);
1231     }
1232     else errmess = new String("Parameter n0.%d (%s) not an Enumeration");
1233   }
1234   else errmess = new String("Parameter n0.%d (%s) absent");
1235
1236   if (errmess.IsNull()) return Standard_True;
1237   sprintf (txtmes,errmess->ToCString(),nump,mess);
1238   if (warn) ach->AddWarning(txtmes,errmess->ToCString());
1239   else ach->AddFail(txtmes,errmess->ToCString());
1240   return Standard_False;
1241 }
1242
1243
1244 //=======================================================================
1245 //function : FailEnumValue
1246 //purpose  : 
1247 //=======================================================================
1248
1249 void  StepData_StepReaderData::FailEnumValue(const Standard_Integer /* num */,
1250                                              const Standard_Integer nump,
1251                                              const Standard_CString mess,
1252                                              Handle(Interface_Check)& ach) const
1253 {
1254   Handle(String) errmess =
1255     new String("Parameter n0.%d (%s) : Incorrect Enumeration Value");
1256   sprintf (txtmes,errmess->ToCString(),nump,mess);
1257   ach->AddFail(txtmes,errmess->ToCString());
1258 }
1259
1260
1261 //=======================================================================
1262 //function : ReadEnum
1263 //purpose  : 
1264 //=======================================================================
1265
1266 Standard_Boolean StepData_StepReaderData::ReadEnum(const Standard_Integer num,
1267                                                    const Standard_Integer nump,
1268                                                    const Standard_CString mess,
1269                                                    Handle(Interface_Check)& ach,
1270                                                    const StepData_EnumTool& enumtool,
1271                                                    Standard_Integer& val) const
1272 {
1273 //  reprendre avec ReadEnumParam ?
1274   Handle(String) errmess;  // Null si pas d erreur
1275   Standard_Boolean warn = Standard_False;
1276   if (nump > 0 && nump <= NbParams(num)) {
1277     const Interface_FileParameter& FP = Param(num,nump);
1278     if (FP.ParamType() == Interface_ParamEnum) {
1279       val = enumtool.Value (FP.CValue());
1280       if (val >= 0) return Standard_True;
1281       else errmess = new String("Parameter n0.%d (%s) : Incorrect Enumeration Value");
1282       warn = (acceptvoid > 0);
1283     }
1284     else if (FP.ParamType() == Interface_ParamVoid) {
1285       val = enumtool.NullValue();
1286       if (val < 0) errmess =
1287         new String("Parameter n0.%d (%s) : Undefined Enumeration not allowed");
1288       warn = (acceptvoid > 0);
1289     }
1290     else errmess = new String("Parameter n0.%d (%s) not an Enumeration");
1291   }
1292   else errmess = new String("Parameter n0.%d (%s) absent");
1293
1294   if (errmess.IsNull()) return Standard_True;
1295   sprintf (txtmes,errmess->ToCString(),nump,mess);
1296   if (warn)
1297     ach->AddWarning(txtmes,errmess->ToCString());
1298   else 
1299     ach->AddFail(txtmes,errmess->ToCString());
1300   return Standard_False;
1301 }
1302
1303
1304 //=======================================================================
1305 //function : ReadTypedParam
1306 //purpose  : 
1307 //=======================================================================
1308
1309 Standard_Boolean StepData_StepReaderData::ReadTypedParam(const Standard_Integer num,
1310                                                          const Standard_Integer nump,
1311                                                          const Standard_Boolean mustbetyped,
1312                                                          const Standard_CString mess,
1313                                                          Handle(Interface_Check)& ach,
1314                                                          Standard_Integer& numr,
1315                                                          Standard_Integer& numrp,
1316                                                          TCollection_AsciiString& typ) const
1317 {
1318   Handle(String) errmess;  // Null si pas d erreur
1319   if (nump > 0 && nump <= NbParams(num)) {
1320     const Interface_FileParameter& FP = Param(num,nump);
1321     if (FP.ParamType() != Interface_ParamSub) {
1322       //    Pas une sous-liste : OK si admis
1323       numr = num;  numrp = nump;  typ.Clear();
1324       if (mustbetyped) {
1325         errmess = new String("Parameter n0.%d (%s) : single, not typed");
1326         sprintf (txtmes,errmess->ToCString(),nump,mess);
1327         ach->AddFail(txtmes,errmess->ToCString());
1328         return Standard_False;
1329       }
1330       return Standard_True;
1331     }
1332     numr = FP.EntityNumber();  numrp = 1;
1333     if (NbParams(numr) != 1) errmess =
1334       new String("Parameter n0.%d (%s) : SubList, not typed");
1335     typ = RecordType(numr);
1336   }
1337   else errmess = new String("Parameter n0.%d (%s) absent");
1338
1339   if (errmess.IsNull()) return Standard_True;
1340   sprintf (txtmes,errmess->ToCString(),nump,mess);
1341   ach->AddFail(txtmes,errmess->ToCString());
1342   return Standard_False;
1343 }
1344
1345
1346 //=======================================================================
1347 //function : CheckDerived
1348 //purpose  : 
1349 //=======================================================================
1350
1351 Standard_Boolean StepData_StepReaderData::CheckDerived(const Standard_Integer num,
1352                                                        const Standard_Integer nump,
1353                                                        const Standard_CString mess,
1354                                                        Handle(Interface_Check)& ach,
1355                                                        const Standard_Boolean errstat) const
1356 {
1357   Handle(String) errmess;  // Null si pas d erreur
1358   Standard_Boolean warn = !errstat;
1359   if (nump > 0 && nump <= NbParams(num)) {
1360     if (!strcmp(Param(num,nump).CValue(),"*")) return Standard_True;
1361     else errmess = new String("Parameter n0.%d (%s) not Derived");
1362     if (acceptvoid) warn = Standard_True;
1363   }
1364   else errmess = new String("Parameter n0.%d (%s) absent");
1365
1366   if (errmess.IsNull()) return Standard_True;
1367   sprintf (txtmes,errmess->ToCString(),nump,mess);
1368   if (warn) ach->AddWarning (txtmes,errmess->ToCString());
1369   else      ach->AddFail    (txtmes,errmess->ToCString());
1370   return Standard_False;
1371 }
1372
1373
1374 //  #########################################################################
1375 // ....     Methodes specifiques (demandees par FileReaderData)     .... //
1376
1377
1378 //=======================================================================
1379 //function : NbEntities
1380 //purpose  : 
1381 //=======================================================================
1382
1383 Standard_Integer StepData_StepReaderData::NbEntities () const  // redefined
1384 {
1385   return thenbents;
1386 }
1387
1388
1389 //=======================================================================
1390 //function : FindNextRecord
1391 //purpose  : 
1392 //=======================================================================
1393
1394 Standard_Integer StepData_StepReaderData::FindNextRecord
1395   (const Standard_Integer num) const
1396 {
1397   // retourne, sur un numero d enregistrement donne (par num), le suivant qui
1398   // definit une entite, ou 0 si c est fini :
1399   // passe le Header (nbhend premiers records) et
1400   // saute les enregistrements SCOPE et ENDSCOPE et les SOUS-LISTES
1401
1402   if (num < 0) return 0 ;
1403   Standard_Integer num1 = num + 1 ; if (num == 0) num1 = thenbhead + 1;
1404   Standard_Integer max = NbRecords() ;
1405
1406   while (num1 <= max ) {
1407     if (theidents(num1) > 0) return num1;
1408
1409     // SCOPE,ENDSCOPE et Sous-Liste ont un identifieur fictif: -1,-2 respectivement
1410     // et SUBLIST ont un negatif. Seule une vraie entite a un Ident positif
1411     num1 ++ ;
1412   }
1413   return 0;
1414 }
1415
1416
1417 //=======================================================================
1418 //function : FindEntityNumber
1419 //purpose  : 
1420 //=======================================================================
1421
1422 Standard_Integer StepData_StepReaderData::FindEntityNumber(const Standard_Integer num,
1423                                                            const Standard_Integer id) const
1424 {
1425   //  Soit un "Id" : recherche dans les Parametres de type Ident de <num>,
1426   //  si un d eux designe #Id justement. Si oui, retourne son EntityNumber
1427   if (num == 0) return 0;
1428   Standard_Integer nb = NbParams(num);
1429   for (Standard_Integer i = 1; i <= nb; i ++) {
1430     const Interface_FileParameter& FP = Param(num,i);
1431     if (FP.ParamType() != Interface_ParamIdent) continue;
1432     Standard_Integer ixp = atoi( &FP.CValue()[1] );
1433     if (ixp == id) return FP.EntityNumber();
1434   }
1435   return 0;    // ici, pas trouve
1436 }
1437
1438
1439 //  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##
1440 // ....         La fonction qui suit merite une attention speciale        ....
1441
1442
1443 //  Cette methode precharge les EntityNumbers dans les Params : ils designent
1444 //  les Entites proprement dites dans la liste lue par BoundEntity
1445 //  Interet : adresse de meme les sous-listes (Num->no record dans le Direc)
1446 //  resultat exploite par ParamEntity et ParamNumber
1447
1448 //  En l absence de SCOPE, ou si les "ident" sont strictement ordonnes, a coup
1449 //  sur ils ne sont pas dupliques, on peut utiliser une IndexedMap en toute
1450 //  confiance. Sinon, il faut balayer dans le fichier, mais avec les SCOPES
1451 //  cela va beaucoup plus vite (s ils sont assez gros) : on s y retrouve.
1452
1453 // Pour la recherche par balayage, On opere en plusieurs etapes
1454 // Avant toute chose, le chargement a deja fait une preparation : les idents
1455 // (Entity, SubList) sont deja en entiers (rapidite de lecture), en particulier
1456 // dans les EntityNumber : ainsi, on lit cet ident, on le traite, et on remet
1457 // a la place un vrai numero de Record
1458 //
1459 // D abord, on passe le directory en table d entiers,  sous-listes expurgees
1460 // en // , table inverse vers cette table, car les sous-listes peuvent par
1461 // contre designer des objets ...
1462
1463 // Pour les sous-listes, on exploite leur mode de construction : elles sont
1464 // enregistrees AVANT d etre referencees. Un tableau "subn" note donc pour
1465 // chaque numero de sous-liste (relatif a une entite qui suit, et reference
1466 // par elle ou une autre sous-liste qui suit egalement), son n0 de record
1467 // REMARQUE : ceci marche aussi pour le Header, traite par l occasion
1468
1469
1470 //=======================================================================
1471 //function : SetEntityNumbers
1472 //purpose  : 
1473 //=======================================================================
1474
1475 void StepData_StepReaderData::SetEntityNumbers(const Standard_Boolean withmap)
1476 {
1477   Handle(Message_Messenger) sout = Message::DefaultMessenger();
1478 //   Passe initiale : Resolution directe par Map
1479 //   si tout passe (pas de collision), OK. Sinon, autres passes a prevoir
1480 //   On resoud du meme coup les sous-listes
1481   Standard_Integer nbdirec = NbRecords() ;
1482   Standard_Integer *subn = new Standard_Integer[thelastn+1];
1483
1484   Standard_Boolean pbmap = Standard_False;        // au moins un conflit
1485   Standard_Integer nbmap = 0;
1486   TColStd_IndexedMapOfInteger imap(thenbents);
1487   Standard_Integer *indm;    // Index Map -> Record Number (seulement si map)
1488   indm = new Standard_Integer[nbdirec+1];
1489
1490   Standard_Integer num; // svv Jan11 2000 : porting on DEC
1491   for (num = 1 ; num <= nbdirec ; num ++) {
1492     Standard_Integer ident = theidents(num);
1493     if (ident > 0) {      // Ident normal -> Map ?
1494 //  Map : si Recouvrement, l inhiber. Sinon, noter index
1495       Standard_Integer indmap = imap.Add(ident);
1496       if (indmap <= nbmap) {
1497         indmap = imap.FindIndex(ident);    // plus sur
1498         indm[indmap] = -1;      // Map -> pb
1499         pbmap = Standard_True;
1500 //  pbmap signifie qu une autre passe sera necessaire ...
1501       } else {
1502         nbmap = indmap;
1503         indm[indmap] = num;      // Map ->ident
1504       }
1505     }
1506   }
1507
1508   for (num = 1 ; num <= nbdirec ; num ++) {
1509     Standard_Integer ident = theidents(num);
1510     if (ident < -2) subn[-(ident+2)] = num;  // toujours a jour ...
1511
1512     Standard_Integer nba = NbParams(num) ;
1513     Standard_Integer nda = (num == 1 ? 0 : ParamFirstRank(num-1));
1514     
1515     for (Standard_Integer na = nba ; na > 0 ; na --) {
1516 //    On traite : les sous-listes (sf subn), les idents (si Map dit OK ...)
1517       Interface_FileParameter& FP = ChangeParameter (nda+na);
1518 //      Interface_FileParameter& FP = ChangeParam (num,na);
1519       Interface_ParamType letype = FP.ParamType();
1520       if (letype == Interface_ParamSub) {
1521         Standard_Integer numsub = FP.EntityNumber();
1522         if (numsub > thelastn) {
1523           sout<<"Bad Sub.N0, Record "<<num<<" Param "<<na<<":$"<<numsub<<endl;
1524           continue;
1525         }
1526         FP.SetEntityNumber(subn[numsub]);
1527       } else if (letype == Interface_ParamIdent) {
1528         Standard_Integer id = FP.EntityNumber();
1529         Standard_Integer indmap = imap.FindIndex(id);
1530         if (indmap > 0) {                  // la map a trouve
1531           Standard_Integer num0 = indm[indmap];
1532           if (num0 > 0) FP.SetEntityNumber(num0);  // ET VOILA, on a resolu
1533           else FP.SetEntityNumber(-id);   // CONFLIT -> faudra resoudre ...
1534         } else {                          // NON RESOLU, si pas pbmap, le dire
1535           FP.SetEntityNumber(-id);
1536           if (pbmap) continue;            // pbmap : on se retrouvera
1537           char failmess[100];
1538 //  ...  Construire le Check  ...
1539           sprintf(failmess,
1540             "Unresolved Reference, Ent.Id.#%d Param.n0 %d (Id.#%d)",
1541                   ident,na,id);
1542           thecheck->AddFail(failmess,"Unresolved Reference");
1543 //  ...  Et sortir message un peu plus complet
1544           sout << "*** ERR StepReaderData *** Pour Entite #"<< ident
1545             << "\n    Type:" << RecordType(num)
1546             << "  Param.n0 " << na << ": #" << id << " Non trouve" << endl ;
1547         }      // FIN  Mapping
1548       }        // FIN  Traitement Reference
1549     }          // FIN  Boucle Parametres
1550   }            // FIN  Boucle Repertoires
1551
1552   delete [] subn;
1553   if (!pbmap) {
1554     delete [] indm;  return;
1555   }
1556   sout << " --  2nd pass required --";
1557
1558   Standard_Integer nbseq = thenbents+2*thenbscop;
1559   Standard_Integer *inds = new Standard_Integer[nbseq+1];   // n0 Record/Entite
1560   Standard_Integer *indi = new Standard_Integer[nbseq+1];   // Idents/scopes
1561   Standard_Integer *indr = new Standard_Integer[nbdirec+1]; // inverse de nds
1562   Standard_Integer *indx = NULL;                  // pour EXPORT (silya)
1563
1564   imap.Clear();
1565   Standard_Boolean iamap = withmap;               // (par defaut True)
1566   nbmap = 0;
1567
1568   TColStd_SequenceOfInteger scopile;  // chainage des scopes note par pile
1569   Standard_Integer nr = 0 ;
1570   for (num = 1 ; num <= nbdirec ; num ++) {
1571     Standard_Integer ident = theidents(num);
1572     if (ident < -2) {             // SOUS-LISTE (cas le plus courant)
1573       indr[num] = nr + 1;         // recherche basee sur nr (objet qui suit)
1574     } else if (ident >= 0) {      // Ident normal
1575       nr ++;  inds[nr] = num;  indi[nr] = ident; indr[num] = nr;
1576       if (ident > 0) {   // et non (iamap && ident > 0)
1577 //  Map : si Recouvrement, l inhiber. Sinon, noter index
1578         Standard_Integer indmap = imap.Add(ident);
1579         if (indmap <= nbmap) {
1580           Standard_Boolean errorscope = Standard_False;
1581           indmap = imap.FindIndex(ident);    // plus sur
1582           pbmap = Standard_True;
1583           if (thenbscop == 0) errorscope = Standard_True;
1584 //  Numeros identiques alors quilnya pas de SCOPE ? ERREUR !
1585 //  (Bien sur, silya des SCOPES, on passe au travers, mais bon...)
1586           else {
1587 //  Silya des SCOPES, tachons d y voir de plus pres pour signaler un probleme
1588 //  Erreur si MEME groupe SCOPE
1589 //  ATTENTION, on recherche, non dans tous les records, mais dans les records
1590 //    CHAINES, cf nr et non num (pas de sous-liste, chainage scope-endscope)
1591             Standard_Integer fromscope  = nr;
1592             Standard_Integer toscope    = indm[indmap];
1593             if (toscope < 0) toscope = -toscope;
1594             while (1) {
1595               fromscope --;    // iteration de base
1596               if (fromscope <= toscope) {
1597                 errorscope = Standard_True;  // BANG, on est dessus
1598                 break;
1599               }
1600               Standard_Integer idtest = indi[fromscope];
1601               if (idtest >=  0) continue;  // le suivant (enfin, le precedent)
1602               if (idtest == -1) break;     // pas meme niveau, donc c est OK
1603               if (idtest == -3) {
1604                 fromscope = inds[fromscope];
1605                 if (fromscope < toscope) break;  // on sort, pas en meme niveau
1606               }
1607             }
1608           }
1609           if (errorscope) {
1610 //  On est dedans : le signaler
1611             char ligne[80];
1612             sprintf(ligne,"Ident defined SEVERAL TIMES : #%d",ident);
1613             thecheck->AddFail(ligne,"Ident defined SEVERAL TIMES : #%d");
1614             sout << "StepReaderData:SetEntityNumbers, " << ligne << endl;
1615           }
1616           if (indm[indmap] > 0) indm[indmap] = -indm[indmap];  // Pas pour Map
1617 //  Cas Normal pour la Map
1618         } else {
1619           nbmap = indmap;
1620           indm[indmap] = nr;      // Map ->(indm)->inds
1621         }
1622       }
1623     } else if (ident == -1) {     // SCOPE
1624       nr ++;  inds[nr] = num;  indi[nr] = -1;    indr[num] = 0;
1625       scopile.Append(nr) ;
1626     } else if (ident == -2) {     // ENDSCOPE
1627       Standard_Integer nscop = scopile.Last() ;     // chainage SCOPE-ENDSCOPE
1628       scopile.Remove(scopile.Length()) ;
1629       nr ++; inds[nr] = nscop; indi[nr] = -3; indr[num] = 0; inds[nscop] = nr;
1630       if (NbParams(num) > 0) {
1631 //  EXPORT : traitement special greffe sur celui de SCOPE (sans le perturber)
1632         if (!indx) {
1633           indx = new Standard_Integer[nbseq+1];
1634           for (Standard_Integer ixp = 0; ixp <= nbseq; ixp ++) indx[ixp] = 0;
1635         }
1636         indx[nr] = num;  indx[nscop] = num;
1637       }
1638     } else if (ident == 0) {      // HEADER
1639       indr[num] = 0;
1640     }
1641   }
1642
1643 //  ..    Resolution des EXPORT, silyena et silya besoin    ..
1644 //  Pour chaque valeur de EXPORT qui n a pas ete resolue par la MAP,
1645 //  determiner sa position locale par recherche en arriere depuis ENDSCOPE
1646   if ((!iamap || pbmap) && indx) {
1647     for (nr = 0; nr <= nbseq; nr ++) {
1648       if (indx[nr] == 0 && indi[nr] != -3) continue;  // ENDSCOPE + EXPORT
1649       num = indx[nr];
1650       Standard_Integer nba = NbParams(num);
1651       for (Standard_Integer na = 1; na <= nba; na ++) {
1652         Interface_FileParameter& FP = ChangeParam (num,na);
1653         if (FP.ParamType() != Interface_ParamIdent) continue;
1654         Standard_Integer id = - FP.EntityNumber();
1655         if (id < 0) continue;    // deja resolu en tete
1656 /*      if (imap.Contains(id)) {            et voila
1657           FP.SetEntityNumber(indm[imap.FindIndex(id)]);
1658           continue;
1659         }    */
1660
1661 //  Recherche du Id demande : si EXPORT imbrique, deja resolu mais il faut
1662 //  regarder ! (inutile par contre d aller y voir : c est deja fait, car
1663 //  un EXPORT imbrique a ete traite AVANT celui qui imbrique)
1664         Standard_Integer n0 = nr-1 ;
1665         if (indi[n0] == -3) n0 --;         // si on suit juste un ENDSCOPE
1666         while (n0  > 0) {
1667           Standard_Integer irec = indi[n0];
1668           if (irec == id) {                // trouve
1669             FP.SetEntityNumber(inds[n0]);
1670             break ;
1671           }
1672           if (irec == -1) break;           // SCOPE : fin de ce SCOPE/ENDSCOPE
1673           if (irec == -3) {
1674 //  gare a EXPORT : si un EXPORT detient Id, noter son Numero deja calcule
1675 //  Attention : Id a lire depuis CValue  car EntityNumber deja resolu
1676             Standard_Integer nok = FindEntityNumber (indx[n0],id);
1677             if (nok > 0) {
1678               FP.SetEntityNumber(nok);
1679               break;
1680             }
1681             n0 = inds[n0];   // ENDSCOPE ou EXPORT infructueux : le sauter
1682           }      // fin traitement sur un ENDSCOPE ou EXPORT
1683           n0 -- ;
1684         }        // fin resolution d un Parametre EXPORT
1685       }          // fin resolution de la liste d un EXPORT
1686     }            // fin bouclage sur les EXPORT
1687   }
1688
1689 //  Exploitation de la table : bouclage porte sur la table
1690
1691 //  Traitement des sous-listes : se fait dans la foulee, par gestion d une pile
1692 //  basee sur la constitution des sous-listes
1693   Standard_Integer maxsubpil = 30;  // pile simulee avec un Array : tres fort
1694   Handle(TColStd_HArray1OfInteger) subpile =  // ... gagne de la memoire ...
1695     new TColStd_HArray1OfInteger (1,maxsubpil);
1696   Standard_Integer nbsubpil = 0;              // ... et tellement plus rapide !
1697
1698   for (num = 1 ; num <= nbdirec ; num ++) {
1699     nr = indr[num];
1700     if (nr == 0) continue;  //    pas un objet ou une sous-liste
1701     Standard_Integer nba = NbParams(num) ;
1702     for (Standard_Integer na = nba ; na > 0 ; na --) {
1703 //  On lit depuis la fin : cela permet de traiter les sous-listes dans la foulee
1704 //  Sinon, on devrait noter qu il y a eu des sous-listes et reprendre ensuite
1705
1706       Interface_FileParameter& FP = ChangeParam (num,na);
1707       Interface_ParamType letype = FP.ParamType();
1708       if (letype == Interface_ParamSub) {
1709 //  parametre type sous-liste : numero de la sous-liste lu par depilement
1710         FP.SetEntityNumber(subpile->Value(nbsubpil));
1711         nbsubpil --;   //       subpile->Remove(nbsubpil);
1712
1713       } else if (letype == Interface_ParamIdent) {
1714 //  parametre type ident (reference une entite) : chercher ident demande
1715         Standard_Integer id = - FP.EntityNumber();
1716         if (id < 0) continue;    // deja resolu en tete
1717
1718 // Voila : on va chercher id dans ndi; algorithme de balayage
1719         Standard_Integer pass, sens, nok,  n0,irec;     pass = sens = nok = 0;
1720         if (!iamap) pass = 1;                  // si map non disponible
1721         while (pass < 3) {
1722           pass ++ ;
1723 //    MAP disponible
1724           if (pass == 1) {                     // MAP DISPONIBLE
1725             Standard_Integer indmap = imap.FindIndex(id);
1726             if (indmap > 0) {                  // la map a trouve
1727               nok = indm[indmap];
1728               if (nok < 0) continue;           // CONFLIT -> faut resoudre ...
1729               break;
1730             }
1731             else continue;
1732           }
1733 //    1re Passe : REMONTEE -> Debut fichier
1734           if (sens == 0 && nr > 1) {
1735             n0 = nr-1 ;
1736             if (indi[n0] == -3) n0 --;         // si on suit juste un ENDSCOPE
1737             while (n0  > 0) {
1738               irec = indi[n0];
1739               if (irec == id) {                // trouve
1740                 nok = n0 ; break ;
1741               }
1742 //    ENDSCOPE : Attention a EXPORT sinon sauter
1743               if (irec == -3) {
1744                 if (!indx) n0 = inds[n0];
1745                 else {
1746 //    EXPORT, il faut regarder
1747                   nok = FindEntityNumber (indx[n0],id);
1748                   if (nok > 0) break;
1749                   n0 = inds[n0];               // ENDSCOPE : le sauter
1750                 }
1751               }
1752               n0 -- ;
1753             }
1754 //    2me Passe : DESCENTE -> Fin fichier
1755           } else if (nr < nbseq) {             // descente -> fin fichier
1756             n0 = nr+1 ;
1757             while (n0 <= nbseq) {
1758               irec = indi[n0];
1759               if (irec == id) {                // trouve
1760                 nok = n0 ; break ;
1761               }
1762 //    SCOPE : Attention a EXPORT sinon sauter
1763               if (irec == -1) {
1764                 if (!indx) n0 = inds[n0];
1765                 else {
1766 //    EXPORT, il faut regarder
1767                   nok = FindEntityNumber (indx[n0],id);
1768                   if (nok > 0) break;
1769                   n0 = inds[n0];               // SCOPE : le sauter
1770                 }
1771               }
1772               n0 ++ ;
1773             }
1774           }
1775           if (nok > 0) break ;
1776           sens = 1 - sens ;      // passe suivante
1777         }
1778                                  // ici on a nok, numero trouve
1779         if (nok > 0) {
1780           Standard_Integer num0 = inds[nok];
1781           FP.SetEntityNumber(num0);  // ET VOILA, on a resolu
1782
1783                                  // pas trouve : le signaler
1784         } else {
1785 //  Alimenter le Check ...  Pour cela, determiner n0 Entite et Ident
1786           char failmess[100];
1787           Standard_Integer nument = 0;
1788           Standard_Integer n0ent; // svv Jan11 2000 : porting on DEC
1789           for (n0ent = 1; n0ent <= nr; n0ent ++) {
1790             if (indi[n0ent] > 0) nument ++;
1791           }
1792           Standard_Integer ident = RecordIdent(num);
1793           if (ident < 0) {
1794             for (n0ent = num + 1; n0ent <= nbdirec; n0ent ++) {
1795               ident = RecordIdent(n0ent); if (ident > 0) break;
1796             }
1797           }
1798 //  ...  Construire le Check  ...
1799           sprintf(failmess,
1800             "Unresolved Reference, Ent.n0 %d (Id.#%d) Param.n0 %d (Id.#%d)",
1801                   nument,ident,na,id);
1802           thecheck->AddFail(failmess,"Unresolved Reference");
1803 //  ...  Et sortir message un peu plus complet
1804           sout << "*** ERR StepReaderData *** Pour Entite "<<nument
1805             <<", a "<< (nr*100)/nbseq<<"% de DATA : #"<< ident
1806             << "\n    Type:" << RecordType(num)
1807             << "  Param.n0 " << na << ": #" << id << " Non trouve" << endl ;
1808           FP.SetEntityNumber(0);  // -> Reference non resolue
1809         }
1810       }
1811     }
1812 //  Si ce record est lui-meme une sous-liste, empiler !
1813     if (inds[nr] != num) {
1814       if (nbsubpil >= maxsubpil) {
1815         maxsubpil = maxsubpil+30;
1816         Handle(TColStd_HArray1OfInteger) newsubpil =
1817           new TColStd_HArray1OfInteger (1,maxsubpil);
1818         for (Standard_Integer bidpil = 1; bidpil <= maxsubpil - 30; bidpil ++)
1819           newsubpil->SetValue(bidpil,subpile->Value(bidpil));
1820         subpile = newsubpil;
1821       }
1822       nbsubpil ++;
1823       subpile->SetValue(nbsubpil,num);      // Append(num);
1824     }
1825   }
1826   delete [] inds; delete [] indi; delete [] indr;    //  subpile->Detroy();
1827   if (indx) delete [] indx;
1828 }
1829
1830
1831 //  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##  ##
1832 //  ....             Gestion du Header : Preparation, lecture             ....
1833
1834
1835 //=======================================================================
1836 //function : FindNextHeaderRecord
1837 //purpose  : 
1838 //=======================================================================
1839
1840 Standard_Integer StepData_StepReaderData::FindNextHeaderRecord
1841   (const Standard_Integer num) const
1842 {
1843 // retourne, sur un numero d enregistrement donne (par num), le suivant qui
1844 // definit une entite, ou 0 si c est fini :
1845 // Opere comme FindNextRecord mais ne balaie que le Header
1846
1847   if (num < 0) return 0 ;
1848   Standard_Integer num1 = num + 1 ;
1849   Standard_Integer max = thenbhead;
1850
1851   while (num1 <= max ) {
1852 // SCOPE,ENDSCOPE et Sous-Liste ont un identifieur negatif
1853 // Ne retenir que les Idents positifs ou nuls (nul : pas d Ident dans Header)
1854     if ( RecordIdent(num1) >= 0) return num1 ;
1855     num1 ++ ;
1856   }
1857   return 0;
1858 }
1859
1860
1861 //=======================================================================
1862 //function : PrepareHeader
1863 //purpose  : 
1864 //=======================================================================
1865
1866 void StepData_StepReaderData::PrepareHeader ()
1867 {
1868 // Resolution des references : ne concerne que les sous-listes
1869 //  deja faite par SetEntityNumbers donc pas de souci a se faire
1870
1871 /*
1872 // Algorithme repris et adapte de SetEntityNumbers
1873 //  Traitement des sous-listes : se fait dans la foulee, par gestion d une pile
1874 //  basee sur la constitution des sous-listes
1875   TColStd_SequenceOfInteger subpile;
1876   Standard_Integer nbsubpil = 0;     // profondeur de pile mais plus rapide ...
1877
1878   for (Standard_Integer num = 1 ; num <= thenbhead ; num ++) {
1879     Standard_Integer nba = NbParams(num) ;
1880     for (Standard_Integer na = nba ; na > 0 ; na --) {
1881 ..  On lit depuis la fin : cela permet de traiter les sous-listes dans la foulee
1882 ..  Sinon, on devrait noter qu il y a eu des sous-listes et reprendre ensuite
1883
1884       Interface_FileParameter& FP = ChangeParam(num,na);
1885       Interface_ParamType letype = FP.ParamType();
1886       if (letype == Interface_ParamSub) {
1887 ..  parametre type sous-liste : numero de la sous-liste lu par depilement
1888         FP.SetEntityNumber(subpile.Last());
1889 .. ..        SetParam(num,na,FP);
1890         subpile.Remove(nbsubpil);
1891         nbsubpil --;
1892       }
1893     }
1894 .. Si c est une sous-liste, empiler
1895     if (RecordIdent(num) < -2) {
1896       subpile.Append(num);
1897       nbsubpil ++;
1898     }
1899   }
1900 */
1901 }
1902
1903
1904 //=======================================================================
1905 //function : GlobalCheck
1906 //purpose  : 
1907 //=======================================================================
1908
1909 const Handle(Interface_Check)  StepData_StepReaderData::GlobalCheck () const
1910 {
1911   return thecheck;
1912 }