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