Loading files
3d097a032This file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
// List of changes:
// skl 29.01.2003 - deleted one space symbol at the beginning
// of strings from Header Section
#include <Interface_Check.hxx>
#include <Interface_EntityIterator.hxx>
#include <Interface_InterfaceMismatch.hxx>
#include <MoniTool_Macros.hxx>
#include <Interface_ReportEntity.hxx>
#include <Standard_Transient.hxx>
#include <StepData_ESDescr.hxx>
#include <StepData_FieldList.hxx>
#include <StepData_Field.hxx>
#include <StepData_PDescr.hxx>
#include <StepData_Protocol.hxx>
#include <StepData_ReadWriteModule.hxx>
#include <StepData_SelectArrReal.hxx>
#include <StepData_SelectMember.hxx>
#include <StepData_StepModel.hxx>
#include <StepData_StepWriter.hxx>
#include <StepData_UndefinedEntity.hxx>
#include <StepData_WriterLib.hxx>
#include <TCollection_AsciiString.hxx>
#include <TCollection_HAsciiString.hxx>
#include <cstdio>
#define StepLong 72
// StepLong: maximum length of a Step file line
// Literal constants (useful for performance AND MEMORY)
static TCollection_AsciiString textscope(" &SCOPE");
static TCollection_AsciiString textendscope(" ENDSCOPE");
static TCollection_AsciiString textcomm(" /* ");
static TCollection_AsciiString textendcomm(" */");
static TCollection_AsciiString textlist("(");
static TCollection_AsciiString textendlist(")");
static TCollection_AsciiString textendent(");");
static TCollection_AsciiString textparam(",");
static TCollection_AsciiString textundef("$");
static TCollection_AsciiString textderived("*");
static TCollection_AsciiString texttrue(".T.");
static TCollection_AsciiString textfalse(".F.");
static TCollection_AsciiString textunknown(".U.");
//=================================================================================================
StepData_StepWriter::StepData_StepWriter(const occ::handle<StepData_StepModel>& amodel)
: thecurr(StepLong),
thefloatw(12)
{
themodel = amodel;
thelabmode = thetypmode = 0;
thefile = new NCollection_HSequence<occ::handle<TCollection_HAsciiString>>();
thesect = false;
thefirst = true;
themult = false;
thecomm = false;
thelevel = theindval = 0;
theindent = false;
// Floating point format: delegated to FloatWriter
}
// .... Float Sending Control ....
//=================================================================================================
Interface_FloatWriter& StepData_StepWriter::FloatWriter()
{
return thefloatw;
} // refer to it
//=================================================================================================
int& StepData_StepWriter::LabelMode()
{
return thelabmode;
}
//=================================================================================================
int& StepData_StepWriter::TypeMode()
{
return thetypmode;
}
// .... Scope Description (BEFORE Sending) ....
//=================================================================================================
void StepData_StepWriter::SetScope(const int numscope, const int numin)
{
int nb = themodel->NbEntities();
if (numscope <= 0 || numscope > nb || numin <= 0 || numin > nb)
{
throw Interface_InterfaceMismatch("StepWriter : SetScope, out of range");
}
if (thescopenext.IsNull())
{
thescopebeg = new NCollection_HArray1<int>(1, nb);
thescopebeg->Init(0);
thescopeend = new NCollection_HArray1<int>(1, nb);
thescopeend->Init(0);
thescopenext = new NCollection_HArray1<int>(1, nb);
thescopenext->Init(0);
}
else if (thescopenext->Value(numin) != 0)
{
#ifdef OCCT_DEBUG
std::cout << "StepWriter : SetScope (scope : " << numscope << " entity : " << numin
<< "), Entity already in a Scope" << std::endl;
#endif
throw Interface_InterfaceMismatch("StepWriter : SetScope, already set");
}
thescopenext->SetValue(numin, -1); // new end of scope
if (thescopebeg->Value(numscope) == 0)
{
thescopebeg->SetValue(numscope, numin);
}
int lastin = thescopeend->Value(numscope);
if (lastin > 0)
{
thescopenext->SetValue(lastin, numin);
}
thescopeend->SetValue(numscope, numin);
}
//=================================================================================================
bool StepData_StepWriter::IsInScope(const int num) const
{
if (thescopenext.IsNull())
{
return false;
}
return (thescopenext->Value(num) != 0);
}
// ###########################################################################
// ## ## ## ## SENDING SECTIONS ## ## ## ##
// .... Sending Complete Model ....
//=================================================================================================
void StepData_StepWriter::SendModel(const occ::handle<StepData_Protocol>& protocol,
const bool headeronly)
{
StepData_WriterLib lib(protocol);
if (!headeronly)
{
thefile->Append(new TCollection_HAsciiString("ISO-10303-21;"));
}
SendHeader();
// .... Header: sequence of entities without Ident ....
Interface_EntityIterator header = themodel->Header();
thenum = 0;
for (header.Start(); header.More(); header.Next())
{
const occ::handle<Standard_Transient>& anent = header.Value();
// Write Entity via Lib (similaire a SendEntity)
occ::handle<StepData_ReadWriteModule> module;
int CN;
if (lib.Select(anent, module, CN))
{
if (module->IsComplex(CN))
{
StartComplex();
}
else
{
TCollection_AsciiString styp;
if (thetypmode > 0)
{
styp = module->ShortType(CN);
}
if (styp.Length() == 0)
{
styp = module->StepType(CN);
}
StartEntity(styp);
}
module->WriteStep(CN, *this, anent);
if (module->IsComplex(CN))
{
EndComplex();
}
}
else
{
// Not found above ... try UndefinedEntity
DeclareAndCast(StepData_UndefinedEntity, und, anent);
if (und.IsNull())
{
continue;
}
if (und->IsComplex())
{
StartComplex();
}
und->WriteParams(*this);
if (und->IsComplex())
{
EndComplex();
}
}
EndEntity();
}
EndSec();
if (headeronly)
{
return;
}
// Data: Like Header but with Idents ... otherwise the code is the same
SendData();
// .... Global Errors (if any) ....
occ::handle<Interface_Check> achglob = themodel->GlobalCheck();
int nbfails = achglob->NbFails();
if (nbfails > 0)
{
Comment(true);
SendComment("GLOBAL FAIL MESSAGES, recorded at Read time :");
for (int ifail = 1; ifail <= nbfails; ifail++)
{
SendComment(achglob->Fail(ifail));
}
Comment(false);
NewLine(false);
}
// .... Output Entities one by one ....
int nb = themodel->NbEntities();
for (int i = 1; i <= nb; i++)
{
// Main list: we don't send Entities that are in a Scope
// They will be sent through the Scope that contains them
if (!thescopebeg.IsNull())
{
if (thescopenext->Value(i) != 0)
{
continue;
}
}
SendEntity(i, lib);
}
EndSec();
EndFile();
}
// .... FILE DIVISION INTO SECTIONS ....
//=================================================================================================
void StepData_StepWriter::SendHeader()
{
NewLine(false);
thefile->Append(new TCollection_HAsciiString("HEADER;"));
thesect = true;
}
//=================================================================================================
void StepData_StepWriter::SendData()
{
if (thesect)
{
throw Interface_InterfaceMismatch("StepWriter : Data section");
}
NewLine(false);
thefile->Append(new TCollection_HAsciiString("DATA;"));
thesect = true;
}
//=================================================================================================
void StepData_StepWriter::EndSec()
{
thefile->Append(new TCollection_HAsciiString("ENDSEC;"));
thesect = false;
}
//=================================================================================================
void StepData_StepWriter::EndFile()
{
if (thesect)
{
throw Interface_InterfaceMismatch("StepWriter : EndFile");
}
NewLine(false);
thefile->Append(new TCollection_HAsciiString("END-ISO-10303-21;"));
thesect = false;
}
// .... SENDING AN ENTITY ....
//=================================================================================================
void StepData_StepWriter::SendEntity(const int num, const StepData_WriterLib& lib)
{
char lident[20];
occ::handle<Standard_Transient> anent = themodel->Entity(num);
int idnum = num, idtrue = 0;
// themodel->Number(anent) and/or IdentLabel(anent)
if (thelabmode > 0)
{
idtrue = themodel->IdentLabel(anent);
}
if (thelabmode == 1)
{
idnum = idtrue;
}
if (idnum == 0)
{
idnum = num;
}
if (thelabmode < 2 || idnum == idtrue)
{
Sprintf(lident, "#%d = ", idnum); // skl 29.01.2003
}
else
{
Sprintf(lident, "%d:#%d = ", idnum, idtrue); // skl 29.01.2003
}
// SendIdent reused, lident has just been calculated
thecurr.Clear();
thecurr.Add(lident);
themult = false;
// .... Processing of Potential Scope
if (!thescopebeg.IsNull())
{
int numin = thescopebeg->Value(num);
if (numin != 0)
{
SendScope();
for (int nument = numin; numin > 0; nument = numin)
{
SendEntity(nument, lib);
numin = thescopenext->Value(nument);
}
SendEndscope();
}
}
// .... Sending the Entity proper
// Write Entity via Lib
thenum = num;
occ::handle<StepData_ReadWriteModule> module;
int CN;
if (themodel->IsRedefinedContent(num))
{
// Error Entity: Write the Content + Errors as Comments
occ::handle<Interface_ReportEntity> rep = themodel->ReportEntity(num);
DeclareAndCast(StepData_UndefinedEntity, und, rep->Content());
if (und.IsNull())
{
thechecks.CCheck(num)->AddFail("Erroneous Entity, Content lost");
StartEntity(TCollection_AsciiString("!?LOST_DATA"));
}
else
{
thechecks.CCheck(num)->AddWarning("Erroneous Entity, equivalent content");
if (und->IsComplex())
{
AddString(" (", 2);
}
und->WriteParams(*this);
if (und->IsComplex())
{
AddString(") ", 2);
} // thelevel --; }
}
EndEntity(); // BEFORE Comments
NewLine(false);
Comment(true);
if (und.IsNull())
{
SendComment(" ERRONEOUS ENTITY, DATA LOST");
}
SendComment("On Entity above, Fail Messages recorded at Read time :");
occ::handle<Interface_Check> ach = rep->Check();
int nbfails = ach->NbFails();
for (int ifail = 1; ifail <= nbfails; ifail++)
{
SendComment(ach->Fail(ifail));
}
Comment(false);
NewLine(false);
// Normal case
}
else if (lib.Select(anent, module, CN))
{
if (module->IsComplex(CN))
{
StartComplex();
}
else
{
TCollection_AsciiString styp;
if (thetypmode > 0)
{
styp = module->ShortType(CN);
}
if (styp.Length() == 0)
{
styp = module->StepType(CN);
}
StartEntity(styp);
}
module->WriteStep(CN, *this, anent);
if (module->IsComplex(CN))
{
EndComplex();
}
EndEntity();
}
else
{
// Not found above ... try UndefinedEntity
DeclareAndCast(StepData_UndefinedEntity, und, anent);
if (und.IsNull())
{
return;
}
if (und->IsComplex())
{
StartComplex();
}
und->WriteParams(*this);
if (und->IsComplex())
{
EndComplex();
}
EndEntity();
}
}
// ###########################################################################
// ## ## ## TEXT CONSTITUTION FOR SENDING ## ## ##
// Go to next line. Empty line not counted unless evenempty == true
//=================================================================================================
void StepData_StepWriter::NewLine(const bool evenempty)
{
if (evenempty || thecurr.Length() > 0)
{
thefile->Append(thecurr.Moved());
}
int indst = thelevel * 2;
if (theindent)
{
indst += theindval;
}
thecurr.SetInitial(indst);
thecurr.Clear();
}
// Group current line with previous; remains current except if newline
// == true, in which case we start a new line
// Does nothing if: corresponding total > StepLong or start or end of entity
//=================================================================================================
void StepData_StepWriter::JoinLast(const bool)
{
thecurr.SetKeep();
}
//=================================================================================================
void StepData_StepWriter::Indent(const bool onent)
{
theindent = onent;
}
//=================================================================================================
void StepData_StepWriter::SendIdent(const int ident)
{
char lident[12];
Sprintf(lident, "#%d =", ident);
thecurr.Clear();
thecurr.Add(lident);
themult = false;
}
//=================================================================================================
void StepData_StepWriter::SendScope()
{
AddString(textscope);
}
//=================================================================================================
void StepData_StepWriter::SendEndscope()
{
NewLine(false);
thefile->Append(new TCollection_HAsciiString(textendscope));
}
//=================================================================================================
void StepData_StepWriter::Comment(const bool mode)
{
if (mode && !thecomm)
{
AddString(textcomm, 20);
}
if (!mode && thecomm)
{
AddString(textendcomm);
}
thecomm = mode;
}
//=================================================================================================
void StepData_StepWriter::SendComment(const occ::handle<TCollection_HAsciiString>& text)
{
if (!thecomm)
{
throw Interface_InterfaceMismatch("StepWriter : Comment");
}
AddString(text->ToCString(), text->Length());
}
//=================================================================================================
void StepData_StepWriter::SendComment(const char* const text)
{
if (!thecomm)
{
throw Interface_InterfaceMismatch("StepWriter : Comment");
}
AddString(text, (int)strlen(text));
}
//=================================================================================================
void StepData_StepWriter::StartEntity(const TCollection_AsciiString& atype)
{
if (atype.Length() == 0)
{
return;
}
if (themult)
{
// clang-format off
if (thelevel != 1) { throw Interface_InterfaceMismatch("StepWriter : StartEntity"); // bad parentheses count...
}
// clang-format on
AddString(textendlist);
AddString(" ", 1); // skl 29.01.2003
}
themult = true;
// AddString(" ",1); //skl 29.01.2003
AddString(atype);
thelevel = 0;
theindval = thecurr.Length();
thecurr.SetInitial(0);
thefirst = true;
OpenSub();
}
//=================================================================================================
void StepData_StepWriter::StartComplex()
{
AddString("( ", 2); // skl 29.01.2003
} // thelevel unchanged
//=================================================================================================
void StepData_StepWriter::EndComplex()
{
AddString(") ", 2);
} // thelevel unchanged
// .... SendField and what goes with it
//=================================================================================================
void StepData_StepWriter::SendField(const StepData_Field& fild,
const occ::handle<StepData_PDescr>& descr)
{
const StepData_Field::FieldKind aFieldKind = fild.Kind(false);
if (aFieldKind == StepData_Field::FieldKind::Select)
{
const occ::handle<StepData_SelectMember> sm =
occ::down_cast<StepData_SelectMember>(fild.Transient());
SendSelect(sm, descr);
return;
}
bool isSent = true;
switch (aFieldKind)
{
// here the simple cases; then we cast and see
case StepData_Field::FieldKind::Undefined:
SendUndef();
break;
case StepData_Field::FieldKind::Integer:
Send(fild.Integer());
break;
case StepData_Field::FieldKind::Boolean:
SendBoolean(fild.Boolean());
break;
case StepData_Field::FieldKind::Logical:
SendLogical(fild.Logical());
break;
case StepData_Field::FieldKind::Enum:
SendEnum(fild.EnumText());
break; // enum : descr ?
case StepData_Field::FieldKind::Real:
Send(fild.Real());
break;
case StepData_Field::FieldKind::String:
Send(fild.String());
break;
case StepData_Field::FieldKind::Entity:
Send(fild.Entity());
break;
case StepData_Field::FieldKind::Any:
isSent = false;
break;
case StepData_Field::FieldKind::Derived:
SendDerived();
break;
default:
isSent = false;
break;
}
if (isSent)
{
return;
}
// What remains: the arrays ...
int arity = fild.Arity();
if (arity == 0)
{
SendUndef();
return;
} // PAS NORMAL
if (arity == 1)
{
OpenSub();
const int aLower = fild.Lower();
const int anUpper = aLower + fild.Length() - 1;
for (int anIndex = aLower; anIndex <= anUpper; ++anIndex)
{
const StepData_Field::FieldKind anItemKind = fild.ItemKind(anIndex);
switch (anItemKind)
{
case StepData_Field::FieldKind::Undefined:
SendUndef();
break;
case StepData_Field::FieldKind::Integer:
Send(fild.Integer(anIndex));
break;
case StepData_Field::FieldKind::Boolean:
SendBoolean(fild.Boolean(anIndex));
break;
case StepData_Field::FieldKind::Logical:
SendLogical(fild.Logical(anIndex));
break;
case StepData_Field::FieldKind::Enum:
SendEnum(fild.EnumText(anIndex));
break;
case StepData_Field::FieldKind::Real:
Send(fild.Real(anIndex));
break;
case StepData_Field::FieldKind::String:
Send(fild.String(anIndex));
break;
case StepData_Field::FieldKind::Entity:
Send(fild.Entity(anIndex));
break;
default:
SendUndef();
break; // ANORMAL
}
}
CloseSub();
return;
}
if (arity == 2)
{
OpenSub();
const int aRowLower = fild.Lower(1);
const int anRowUpper = aRowLower + fild.Length(1) - 1;
for (int aRow = aRowLower; aRow <= anRowUpper; ++aRow)
{
const int aColumnLower = fild.Lower(2);
const int aColumnUpper = aColumnLower + fild.Length(2) - 1;
OpenSub();
for (int aColumn = aColumnLower; aColumn <= aColumnUpper; ++aColumn)
{
const StepData_Field::FieldKind anItemKind = fild.ItemKind(aRow, aColumn);
switch (anItemKind)
{
case StepData_Field::FieldKind::Undefined:
SendUndef();
break;
case StepData_Field::FieldKind::Integer:
Send(fild.Integer(aRow, aColumn));
break;
case StepData_Field::FieldKind::Boolean:
SendBoolean(fild.Boolean(aRow, aColumn));
break;
case StepData_Field::FieldKind::Logical:
SendLogical(fild.Logical(aRow, aColumn));
break;
case StepData_Field::FieldKind::Enum:
SendEnum(fild.EnumText(aRow, aColumn));
break;
case StepData_Field::FieldKind::Real:
Send(fild.Real(aRow, aColumn));
break;
case StepData_Field::FieldKind::String:
Send(fild.String(aRow, aColumn));
break;
case StepData_Field::FieldKind::Entity:
Send(fild.Entity(aRow, aColumn));
break;
default:
SendUndef();
break; // ANORMAL
}
}
CloseSub();
}
CloseSub();
return;
}
SendUndef();
}
//=================================================================================================
void StepData_StepWriter::SendSelect(const occ::handle<StepData_SelectMember>& sm,
const occ::handle<StepData_PDescr>& /*descr*/)
{
// SelectMember case. Process the Select then the value
// NB: current processing non-recursive (no SELNAME(SELNAME(..)) )
bool selname = false;
if (sm.IsNull())
{
SendUndef();
return;
}
if (sm->HasName())
{
selname = true;
// SendString (sm->Name());
// AddString(textlist); // SANS AJOUT DE PARAMETRE !!
OpenTypedSub(sm->Name());
}
switch (sm->Kind())
{
case static_cast<int>(StepData_Field::FieldKind::Undefined):
SendUndef();
break;
case static_cast<int>(StepData_Field::FieldKind::Integer):
Send(sm->Integer());
break;
case static_cast<int>(StepData_Field::FieldKind::Boolean):
SendBoolean(sm->Boolean());
break;
case static_cast<int>(StepData_Field::FieldKind::Logical):
SendLogical(sm->Logical());
break;
case static_cast<int>(StepData_Field::FieldKind::Enum):
SendEnum(sm->EnumText());
break; // enum : descr ?
case static_cast<int>(StepData_Field::FieldKind::Real):
Send(sm->Real());
break;
case static_cast<int>(StepData_Field::FieldKind::String):
Send(sm->String());
break;
case static_cast<int>(StepData_Field::FieldKind::Any):
if (occ::is_kind<StepData_SelectArrReal>(sm))
{
SendArrReal(occ::down_cast<StepData_SelectArrReal>(sm)->ArrReal());
}
else
{
SendUndef();
}
break;
default:
SendUndef();
break;
}
if (selname)
{
CloseSub();
}
}
//=================================================================================================
void StepData_StepWriter::SendList(const StepData_FieldList& list,
const occ::handle<StepData_ESDescr>& descr)
{
// start entity ?
int i, nb = list.NbFields();
for (i = 1; i <= nb; i++)
{
occ::handle<StepData_PDescr> pde;
if (!descr.IsNull())
{
pde = descr->Field(i);
}
const StepData_Field& fild = list.Field(i);
SendField(fild, pde);
}
// end entity ?
}
// .... Basic Send* methods
//=================================================================================================
void StepData_StepWriter::OpenSub()
{
AddParam();
AddString(textlist);
thefirst = true;
thelevel++;
}
//=================================================================================================
void StepData_StepWriter::OpenTypedSub(const char* const subtype)
{
AddParam();
if (subtype[0] != '\0')
{
AddString(subtype, (int)strlen(subtype));
}
AddString(textlist);
thefirst = true;
thelevel++;
}
//=================================================================================================
void StepData_StepWriter::CloseSub()
{
AddString(textendlist);
thefirst = false; // the parameter following a sub-list is therefore not first
thelevel--;
}
//=================================================================================================
void StepData_StepWriter::AddParam()
{
if (!thefirst)
{
AddString(textparam);
}
thefirst = false;
}
//=================================================================================================
void StepData_StepWriter::Send(const int val)
{
char lval[12];
AddParam();
Sprintf(lval, "%d", val);
AddString(lval, (int)strlen(lval));
}
//=================================================================================================
void StepData_StepWriter::Send(const double val)
{
// Floating point value, cleaned of trailing "0000" and "E+00"
char lval[24] = {};
int lng = thefloatw.Write(val, lval);
AddParam();
AddString(lval, lng); // handles specific format: if needed
}
// Send(String): note, we send a Text ... so between ' '
//=================================================================================================
void StepData_StepWriter::Send(const TCollection_AsciiString& val)
{
AddParam();
// Use helper function to clean text while preserving control directives
TCollection_AsciiString aVal = CleanTextForSend(val);
int aNn = aVal.Length();
// Add surrounding quotes
aVal.Insert(1, '\'');
aVal.AssignCat('\'');
aNn += 2;
//: i2 abv 31 Aug 98: ProSTEP TR9: avoid wrapping text or do it at spaces
// Watch out for exceeding 72 characters
if (thecurr.CanGet(aNn))
{
AddString(aVal, 0);
//: i2
}
else
{
thefile->Append(thecurr.Moved());
int anIndst = thelevel * 2;
if (theindent)
{
anIndst += theindval;
}
if (anIndst + aNn <= StepLong)
{
thecurr.SetInitial(anIndst);
}
else
{
thecurr.SetInitial(0);
}
if (thecurr.CanGet(aNn))
{
AddString(aVal, 0);
}
else
{
while (aNn > 0)
{
if (aNn <= StepLong)
{
thecurr.Add(aVal); // That's it, we've exhausted everything
thecurr.FreezeInitial();
break;
}
int aStop = StepLong; // position of last separator
for (; aStop > 0 && aVal.Value(aStop) != ' '; aStop--)
{
;
}
if (!aStop)
{
aStop = StepLong;
for (; aStop > 0 && aVal.Value(aStop) != '\\'; aStop--)
{
;
}
if (!aStop)
{
aStop = StepLong;
for (; aStop > 0 && aVal.Value(aStop) != '_'; aStop--)
{
;
}
if (!aStop)
{
aStop = StepLong;
}
}
}
TCollection_AsciiString aBval = aVal.Split(aStop);
thefile->Append(new TCollection_HAsciiString(aVal));
aVal = aBval;
aNn -= aStop;
}
}
}
}
//=================================================================================================
void StepData_StepWriter::Send(const occ::handle<Standard_Transient>& val)
{
char lident[20];
// Undefined ?
if (val.IsNull())
{
// throw Interface_InterfaceMismatch("StepWriter : Sending Null Reference");
thechecks.CCheck(thenum)->AddFail("Null Reference");
SendUndef();
Comment(true);
SendComment(" NUL REF ");
Comment(false);
return;
}
int num = themodel->Number(val);
// String? (if not listed in the Model)
if (num == 0)
{
if (val->IsKind(STANDARD_TYPE(TCollection_HAsciiString)))
{
DeclareAndCast(TCollection_HAsciiString, strval, val);
Send(TCollection_AsciiString(strval->ToCString()));
return;
}
// SelectMember? (always, if not listed)
// but beware, no description attached
else if (val->IsKind(STANDARD_TYPE(StepData_SelectMember)))
{
DeclareAndCast(StepData_SelectMember, sm, val);
occ::handle<StepData_PDescr> descr; // null
SendSelect(sm, descr);
}
// Otherwise, NOT NORMAL!
else
{
thechecks.CCheck(thenum)->AddFail("UnknownReference");
SendUndef();
Comment(true);
SendComment(" UNKNOWN REF ");
Comment(false);
// throw Interface_InterfaceMismatch("StepWriter : Sending Unknown Reference");
}
}
// Normal case: a good Entity, we send its Ident.
else
{
int idnum = num, idtrue = 0;
if (thelabmode > 0)
{
idtrue = themodel->IdentLabel(val);
}
if (thelabmode == 1)
{
idnum = idtrue;
}
if (idnum == 0)
{
idnum = num;
}
if (thelabmode < 2 || idnum == idtrue)
{
Sprintf(lident, "#%d", idnum);
}
else
{
Sprintf(lident, "%d:#%d", idnum, idtrue);
}
AddParam();
AddString(lident, (int)strlen(lident));
}
}
//=================================================================================================
void StepData_StepWriter::SendBoolean(const bool val)
{
if (val)
{
SendString(texttrue);
}
else
{
SendString(textfalse);
}
}
//=================================================================================================
void StepData_StepWriter::SendLogical(const StepData_Logical val)
{
if (val == StepData_LTrue)
{
SendString(texttrue);
}
else if (val == StepData_LFalse)
{
SendString(textfalse);
}
else
{
SendString(textunknown);
}
}
// SendString: note, we give the exact label
//=================================================================================================
void StepData_StepWriter::SendString(const TCollection_AsciiString& val)
{
AddParam();
AddString(val);
}
// SendString: note, we give the exact label
//=================================================================================================
void StepData_StepWriter::SendString(const char* const val)
{
AddParam();
AddString(val, (int)strlen(val));
}
// SendEnum: note, we send an Enum label ... so between . .
//=================================================================================================
void StepData_StepWriter::SendEnum(const TCollection_AsciiString& val)
{
if (val.IsEmpty() || (val.Length() == 1 && val.Value(1) == '$'))
{
SendUndef();
return;
}
AddParam();
TCollection_AsciiString aValue = val;
if (aValue.Value(1) != '.')
{
aValue.Prepend('.');
}
if (aValue.Value(aValue.Length()) != '.')
{
aValue += '.';
}
AddString(aValue, 2);
}
// SendEnum: note, we send an Enum label ... so between . .
//=================================================================================================
void StepData_StepWriter::SendEnum(const char* const val)
{
if (val == nullptr || val[0] == '\0' || (val[0] == '$' && val[1] == '\0'))
{
SendUndef();
return;
}
TCollection_AsciiString aValue(val);
SendEnum(aValue);
}
//=================================================================================================
void StepData_StepWriter::SendArrReal(const occ::handle<NCollection_HArray1<double>>& anArr)
{
if (anArr.IsNull())
{
SendUndef();
return;
}
OpenSub();
for (int anIndex = anArr->Lower(); anIndex <= anArr->Upper(); ++anIndex)
{
Send(anArr->Value(anIndex));
}
CloseSub();
}
//=================================================================================================
void StepData_StepWriter::SendUndef()
{
AddParam();
AddString(textundef);
}
//=================================================================================================
void StepData_StepWriter::SendDerived()
{
AddParam();
AddString(textderived);
}
// EndEntity: if we need to put ; on the line, align it with start of entity ...
//=================================================================================================
void StepData_StepWriter::EndEntity()
{
// clang-format off
if (thelevel != 1) { throw Interface_InterfaceMismatch("StepWriter : EndEntity"); // parentheses count is wrong ...
}
// clang-format on
AddString(textendent);
thelevel = 0; // on garde theindval : sera traite au prochain NewLine
bool indent = theindent;
theindent = false;
NewLine(false);
theindent = indent;
themult = false;
// to force indentation if necessary
}
// current line management (see also NewLine/JoinLine)
//=================================================================================================
void StepData_StepWriter::AddString(const TCollection_AsciiString& astr, const int more)
{
AddString(astr.ToCString(), astr.Length(), more);
}
//=================================================================================================
void StepData_StepWriter::AddString(const char* const astr, const int lnstr, const int more)
{
const auto flushLine = [this](const int theRequired) {
thefile->Append(thecurr.Moved());
int indst = thelevel * 2;
if (theindent)
{
indst += theindval;
}
thecurr.SetInitial(indst < StepLong && indst + theRequired <= StepLong ? indst : 0);
};
if (lnstr + more <= StepLong)
{
while (!thecurr.CanGet(lnstr + more))
{
flushLine(lnstr + more);
}
thecurr.Add(astr, lnstr);
return;
}
int aStart = 0;
int aRest = lnstr;
while (aRest > 0)
{
if (thecurr.CanGet(aRest + more))
{
thecurr.Add(astr + aStart, aRest);
return;
}
const int aRoom = StepLong - thecurr.Length();
if (aRoom <= 0 || (aRest + more <= StepLong && aRoom < aRest + more))
{
flushLine(aRest + more <= StepLong ? aRest + more : 0);
continue;
}
const int aChunk = (aRest < aRoom ? aRest : aRoom);
thecurr.Add(astr + aStart, aChunk);
aStart += aChunk;
aRest -= aChunk;
if (aRest > 0)
{
flushLine(aRest + more <= StepLong ? aRest + more : 0);
}
}
}
// FINAL SENDING
//=================================================================================================
Interface_CheckIterator StepData_StepWriter::CheckList() const
{
return thechecks;
}
//=================================================================================================
int StepData_StepWriter::NbLines() const
{
return thefile->Length();
}
//=================================================================================================
occ::handle<TCollection_HAsciiString> StepData_StepWriter::Line(const int num) const
{
return thefile->Value(num);
}
//=================================================================================================
bool StepData_StepWriter::Print(Standard_OStream& S)
{
bool isGood = (S.good());
int nb = thefile->Length();
for (int i = 1; i <= nb && isGood; i++)
{
S << thefile->Value(i)->ToCString() << "\n";
}
S << std::flush;
isGood = (S && S.good());
return isGood;
}
//=================================================================================================
TCollection_AsciiString StepData_StepWriter::CleanTextForSend(
const TCollection_AsciiString& theText)
{
TCollection_AsciiString aResult;
const int aNb = theText.Length();
// Process characters from beginning to end
for (int anI = 1; anI <= aNb; anI++)
{
const char anUncar = theText.Value(anI);
// Check if we're at the start of a control directive
bool anIsDirective = false;
int aDirectiveLength = 0;
if (anUncar == '\\' && anI <= aNb)
{
// Check for \X2\ and \X4\ patterns first (need exactly 4 characters: \X2\)
if (anI + 3 <= aNb && theText.Value(anI + 1) == 'X' && theText.Value(anI + 3) == '\\')
{
const char aThirdChar = theText.Value(anI + 2);
// \X2, \X4, \X0 patterns - special control sequences
if (aThirdChar == '2' || aThirdChar == '4' || aThirdChar == '0')
{
anIsDirective = true;
aDirectiveLength = 4; // Basic directive length: \X2\, \X4\, \X0\ (4 chars)
// For \X2 and \X4, find the terminating \X0 sequence
if (aThirdChar == '2' || aThirdChar == '4')
{
int aJ = anI + 4;
while (aJ <= aNb - 3)
{
if (theText.Value(aJ) == '\\' && theText.Value(aJ + 1) == 'X'
&& theText.Value(aJ + 2) == '0' && theText.Value(aJ + 3) == '\\')
{
aDirectiveLength = (aJ + 4) - anI; // Include the \X0 sequence
break;
}
aJ++;
}
}
}
}
// Check for \X{HH}\ pattern (need exactly 5 characters: \X{HH}\)
else if (anI + 4 <= aNb && theText.Value(anI + 1) == 'X' && theText.Value(anI + 4) == '\\')
{
const char aThirdChar = theText.Value(anI + 2);
const char aFourthChar = theText.Value(anI + 3);
// Regular \X{HH}\ pattern - check for two hex characters
if (std::isxdigit(aThirdChar) && std::isxdigit(aFourthChar))
{
anIsDirective = true;
aDirectiveLength = 5; // Control directive with two hex chars
}
}
// Check for \S, \N, \T patterns (need exactly 3 characters: \S\)
else if (anI + 2 <= aNb && theText.Value(anI + 2) == '\\')
{
const char aSecondChar = theText.Value(anI + 1);
if (aSecondChar == 'S' || aSecondChar == 'N' || aSecondChar == 'T')
{
anIsDirective = true;
aDirectiveLength = 3; // Simple directive pattern
}
}
// Check for \P{char}\ patterns (need exactly 4 characters: \P{char}\)
else if (anI + 3 <= aNb && theText.Value(anI + 1) == 'P' && theText.Value(anI + 3) == '\\')
{
const char aSecondChar = theText.Value(anI + 2);
if (std::isalpha(aSecondChar))
{
anIsDirective = true;
aDirectiveLength = 4; // P directive with parameter
}
}
}
if (anIsDirective)
{
// Copy the entire directive as-is
for (int aJ = 0; aJ < aDirectiveLength; aJ++)
{
aResult += theText.Value(anI + aJ);
}
anI += aDirectiveLength - 1; // Move past directive (loop will increment by 1)
}
else
{
// Process non-directive characters
if (anUncar == '\'')
{
aResult += "''"; // Double the quote
}
else if (anUncar == '\\')
{
aResult += "\\\\"; // Double the backslash
}
else if (anUncar == '\n')
{
aResult += "\\N\\"; // Convert to directive
}
else if (anUncar == '\t')
{
aResult += "\\T\\"; // Convert to directive
}
else
{
aResult += anUncar; // Copy as-is
}
}
}
return aResult;
}