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