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