-// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE
//
// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
#include "utilities.h"
#include <Basics_Utils.hxx>
+#include <Basics_OCCTVersion.hxx>
#include <TDF_Tool.hxx>
#include <TDF_Data.hxx>
#include <TColStd_DataMapIteratorOfDataMapOfIntegerTransient.hxx>
+#if OCC_VERSION_LARGE < 0x07050000
#include <Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString.hxx>
+#endif
#include <BinDrivers.hxx>
#include <StdDrivers_DocumentRetrievalDriver.hxx>
#define C_SQR_BRACKET ']'
#define PY_NULL "None"
-#ifdef _DEBUG_
-static int MYDEBUG = 0;
-#else
-static int MYDEBUG = 0;
-#endif
-
// VSR 29/08/2017: 0023327, 0023428: eliminate unnecessary lines in Python dump
// Next macro, when defined, causes appearing of SubShapeAllIDs(), SubShapeAllSortedIDs(), GetSameIDs()
// and other such commands in Python dump.
TCollection_AsciiString& theScript,
TCollection_AsciiString& theAfterScript,
const TVariablesList& theVariables,
- const bool theIsPublished,
+ const bool /*theIsPublished*/,
TDF_LabelMap& theProcessed,
std::set<TCollection_AsciiString>& theIgnoreObjs,
bool& theIsDumpCollected);
void Prettify(TCollection_AsciiString& theScript);
+// Helper functions
+namespace
+{
+ // Specifies a way to process a given function
+ enum FunctionProcessType { NOT_PROCESS, TO_PROCESS, UPDATE_DESCRIPTION };
+
+ // Starting string for an edge case where function was dumped from Python code
+ const Standard_CString funcFromPythonStartString = "from salome.geom.geomrepairadv";
+
+
+ //================================================================================
+ /*!
+ * \brief Checks if a description contents a function that was dumped from Python code
+ */
+ //================================================================================
+ bool IsFunctionSetFromPython(const TCollection_AsciiString& aDescr)
+ {
+ // TODO: make it more generic and not depended on geomrepairadv name
+ return aDescr.Search(funcFromPythonStartString) != -1;
+ }
+
+
+ //================================================================================
+ /*!
+ * \brief Removes from description the part before specific import statement
+ */
+ //================================================================================
+ void UpdateFuncFromPythonDescription(TCollection_AsciiString& aDescr)
+ {
+ const Standard_Integer startStringPos = aDescr.Search(funcFromPythonStartString);
+ MESSAGE("Description should start from pos: " << startStringPos);
+ if (startStringPos == -1)
+ {
+ MESSAGE("Can't find a string:\n" << funcFromPythonStartString << " \nin func description!");
+ return;
+ }
+
+ // Remove everything from the beginning till the starting point.
+ // Index starts from 1 not 0!
+ aDescr.Remove(1, startStringPos - 1);
+ MESSAGE("Updated func description: " << aDescr);
+ }
+
+
+ //================================================================================
+ /*!
+ * \brief Finds out how we should process a given function for Python dump
+ */
+ //================================================================================
+ FunctionProcessType GetFunctionProcessingType(const Handle(GEOM_Function)& theFunction, const TDF_LabelMap& theProcessed, const TCollection_AsciiString& aDescr)
+ {
+ MESSAGE("Start check function dependencies...");
+
+ TDF_LabelSequence aSeq;
+ theFunction->GetDependency(aSeq);
+ const Standard_Integer aLen = aSeq.Length();
+
+ for (Standard_Integer i = 1; i <= aLen; i++) {
+ TDF_Label aRefLabel = aSeq.Value(i);
+ Handle(TDF_Reference) aRef;
+ if (!aRefLabel.FindAttribute(TDF_Reference::GetID(), aRef)) {
+ MESSAGE("Can't find TDF_Reference::GetID() attribute. Do not process.");
+ return NOT_PROCESS;
+ }
+
+ if (aRef.IsNull() || aRef->Get().IsNull()) {
+ MESSAGE("Reference to attribute is null. Do not process.");
+ return NOT_PROCESS;
+ }
+
+ Handle(TDataStd_TreeNode) aT;
+ if (!TDataStd_TreeNode::Find(aRef->Get(), aT)) {
+ MESSAGE("Can't find a tree node. Do not process.");
+ return NOT_PROCESS;
+ }
+
+ TDF_Label aDepLabel = aT->Label();
+ Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(aDepLabel);
+ if (aFunction.IsNull()) {
+ MESSAGE("Function is null. Do not process." << aFunction->GetDescription());
+ return NOT_PROCESS;
+ }
+
+ if (!theProcessed.Contains(aDepLabel)) {
+ // Special case for function dumped from Python, because it's appended to
+ // description of other function that should be rejected early.
+ // TODO: it's not clear if we need to check every given function or
+ // checking on this level is enough. At this moment it's better to stay here
+ // for performance reason.
+ if (IsFunctionSetFromPython(aDescr)) {
+ MESSAGE("Function set from Python. Do process with updated description.");
+ return UPDATE_DESCRIPTION;
+ }
+
+ MESSAGE("The dependency label is not in processed list. Do not process.");
+ return NOT_PROCESS;
+ }
+ }
+
+ MESSAGE("OK. Do process the function.");
+ return TO_PROCESS;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Adds function's object to ignored for Python dump output
+ */
+ //================================================================================
+ void AddFuncObjectToIgnored(const Handle(GEOM_Function)& theFunction, std::set<TCollection_AsciiString>& theIgnoreObjs)
+ {
+ TCollection_AsciiString anObjEntry;
+ TDF_Tool::Entry(theFunction->GetOwnerEntry(), anObjEntry);
+ theIgnoreObjs.insert(anObjEntry);
+ }
+
+}
+
+
//================================================================================
/*!
* \brief Fix up the name of python variable
if(!_document)
return false; // document is closed...
+ TDF_Label aLabel = theObject->GetEntry();
+ if ( aLabel == aLabel.Root() )
+ return false; // already removed object
+
//Remove an object from the map of available objects
TCollection_AsciiString anID = BuildIDFromObject(theObject);
if (_objects.IsBound(anID)) {
aNode->Remove();
}
- TDF_Label aLabel = theObject->GetEntry();
aLabel.ForgetAllAttributes(Standard_True);
// Remember the label to reuse it then
{
if(!_document) return false;
- _OCAFApp->SaveAs(_document, theFileName);
+#if defined(WIN32) && defined(UNICODE)
+ std::wstring aFileName = Kernel_Utils::utf8_decode_s(theFileName);
+#else
+ std::string aFileName = theFileName;
+#endif
- return true;
+ return _OCAFApp->SaveAs( _document, aFileName.c_str() ) == PCDM_SS_OK;
}
//=============================================================================
//=============================================================================
bool GEOM_Engine::Load(const char* theFileName)
{
+#if defined(WIN32) && defined(UNICODE)
+ std::wstring aFileName = Kernel_Utils::utf8_decode_s(theFileName);
+#else
+ std::string aFileName = theFileName;
+#endif
Handle(TDocStd_Document) aDoc;
- if (_OCAFApp->Open(theFileName, aDoc) != PCDM_RS_OK) {
+ if (_OCAFApp->Open(aFileName.c_str(), aDoc) != PCDM_RS_OK) {
return false;
}
bool& theIsDumpCollected)
{
theIsDumpCollected = false;
- if (theFunction.IsNull()) return false;
- if (theProcessed.Contains(theFunction->GetEntry())) return false;
+ if (theFunction.IsNull()) {
+ MESSAGE("Can't process a null function! Return.");
+ return false;
+ }
- // pass functions, that depends on nonexisting ones
- bool doNotProcess = false;
- TDF_LabelSequence aSeq;
- theFunction->GetDependency(aSeq);
- Standard_Integer aLen = aSeq.Length();
- for (Standard_Integer i = 1; i <= aLen && !doNotProcess; i++) {
- TDF_Label aRefLabel = aSeq.Value(i);
- Handle(TDF_Reference) aRef;
- if (!aRefLabel.FindAttribute(TDF_Reference::GetID(), aRef)) {
- doNotProcess = true;
- }
- else {
- if (aRef.IsNull() || aRef->Get().IsNull()) {
- doNotProcess = true;
- }
- else {
- Handle(TDataStd_TreeNode) aT;
- if (!TDataStd_TreeNode::Find(aRef->Get(), aT)) {
- doNotProcess = true;
- }
- else {
- TDF_Label aDepLabel = aT->Label();
- Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(aDepLabel);
+ TCollection_AsciiString aDescr = theFunction->GetDescription();
+ MESSAGE("The function description: " << aDescr);
- if (aFunction.IsNull()) doNotProcess = true;
- else if (!theProcessed.Contains(aDepLabel)) doNotProcess = true;
- }
- }
- }
- }
+ if (theProcessed.Contains(theFunction->GetEntry()))
+ return false;
- if (doNotProcess) {
- TCollection_AsciiString anObjEntry;
- TDF_Tool::Entry(theFunction->GetOwnerEntry(), anObjEntry);
- theIgnoreObjs.insert(anObjEntry);
+ // Check if a given function depends on nonexisting ones
+ const FunctionProcessType funcProcessType = GetFunctionProcessingType(theFunction, theProcessed, aDescr);
+ switch (funcProcessType)
+ {
+ case TO_PROCESS:
+ // Just process it
+ break;
+
+ case NOT_PROCESS:
+ {
+ // We don't need this function and its object in a dump
+ AddFuncObjectToIgnored(theFunction, theIgnoreObjs);
return false;
}
+
+ case UPDATE_DESCRIPTION:
+ // Edge case for a function that was dumped from Python.
+ // Get rid of the parent function description.
+ UpdateFuncFromPythonDescription(aDescr);
+ // A result object is already added by an algo script, then
+ // if we keep it in the dump it will be added twice on the script loading.
+ AddFuncObjectToIgnored(theFunction, theIgnoreObjs);
+ break;
+
+ default:
+ MESSAGE("Wrong type of the function processing!" << funcProcessType);
+ break;
+ }
+
theProcessed.Add(theFunction->GetEntry());
- TCollection_AsciiString aDescr = theFunction->GetDescription();
- if(aDescr.Length() == 0) return false;
+ // Check the length only after its fucntion was added to the processed!
+ if(!aDescr.Length())
+ return false;
- //Check if its internal function which doesn't requires dumping
- if(aDescr == "None") return false;
+ // Check if it's an internal function which doesn't require dumping
+ if(aDescr == "None")
+ return false;
//Check the very specific case of RestoreShape function,
//which is not dumped, but the result can be published by the user.
//We do not publish such objects to decrease danger of dumped script failure.
if(aDescr.Value(1) == '#') {
- TCollection_AsciiString anObjEntry;
- TDF_Tool::Entry(theFunction->GetOwnerEntry(), anObjEntry);
- theIgnoreObjs.insert(anObjEntry);
+ AddFuncObjectToIgnored(theFunction, theIgnoreObjs);
return false;
}
//Replace parameter by notebook variables
ReplaceVariables(aDescr,theVariables);
+ // Check description, because we could lose entire command during variable processing
+ if (aDescr.IsEmpty())
+ return false;
//Process sketcher functions, replacing string command by calls to Sketcher interface
if ( ( aDescr.Search( "MakeSketcherOnPlane" ) != -1 ) || ( aDescr.Search( "MakeSketcher" ) != -1 ) ) {
void ReplaceVariables(TCollection_AsciiString& theCommand,
const TVariablesList& theVariables)
{
- if (MYDEBUG)
- cout<<"Command : "<<theCommand<<endl;
+ MESSAGE("Command : " << theCommand);
- if (MYDEBUG) {
- cout<<"All Entries:"<<endl;
+ if (SALOME::VerbosityActivated()) {
+ std::cout<<"All Entries:"<<std::endl;
TVariablesList::const_iterator it = theVariables.begin();
for(;it != theVariables.end();it++)
- cout<<"\t'"<<(*it).first<<"'"<<endl;
+ std::cout<<"\t'"<<(*it).first<<"'"<<std::endl;
}
//Additional case - multi-row commands
if( aCommand.Length() == 0 )
break;
- if (MYDEBUG)
- cout<<"Sub-command : "<<aCommand<<endl;
+ MESSAGE("Sub-command : " << aCommand);
Standard_Integer aStartCommandPos = theCommand.Location(aCommand,1,theCommand.Length());
Standard_Integer aEndCommandPos = aStartCommandPos + aCommand.Length();
//Remove white spaces
anEntry.RightAdjust();
anEntry.LeftAdjust();
- if(MYDEBUG)
- cout<<"Result entry : '" <<anEntry<<"'"<<endl;
+ MESSAGE("Result entry : '" << anEntry << "'");
if ( anEntry.IsEmpty() ) {
aCommandIndex++;
anEntry.Remove( 1, 1 );
anEntry.RightAdjust();
anEntry.LeftAdjust();
- if(MYDEBUG)
- cout<<"Sub-entry : '" <<anEntry<<"'"<<endl;
+ MESSAGE("Sub-entry : '" << anEntry << "'");
}
//Find variables used for object construction
aStates = (*it).second;
if(!aStates) {
- if(MYDEBUG)
- cout<<"Valiables list empty!!!"<<endl;
+ MESSAGE("Can't find an entry among study objects!");
+ // We can't skip this because the entry can be used with automatically assigned name
+ // like "geomObj_1" to create other objects. Some tests will fail without this.
+ // MESSAGE("Can't find an entry among study objects! Skip this command.");
+ // theCommand.Remove(aStartCommandPos, aEndCommandPos - aStartCommandPos);
aCommandIndex++;
+
continue;
}
TState aVariables = aStates->GetCurrectState();
- if(MYDEBUG) {
- cout<<"Variables from SObject:"<<endl;
- for (int i = 0; i < aVariables.size();i++)
- cout<<"\t Variable["<<i<<"] = "<<aVariables[i].myVariable<<endl;
+ if(SALOME::VerbosityActivated()) {
+ std::cout<<"Variables from SObject:"<<std::endl;
+ for (size_t i = 0; i < aVariables.size();i++)
+ std::cout<<"\t Variable["<<i<<"] = "<<aVariables[i].myVariable<<std::endl;
}
//Calculate total number of parameters
while(aCommand.Location(aTotalNbParams,COMMA,1,aCommand.Length()))
aTotalNbParams++;
- if(MYDEBUG)
- cout<<"aTotalNbParams = "<<aTotalNbParams<<endl;
+ MESSAGE("aTotalNbParams = " << aTotalNbParams);
Standard_Integer aFirstParam = aNbEntries;
//Replace parameters by variables
Standard_Integer aStartPos = 0;
Standard_Integer aEndPos = 0;
- int iVar = 0;
+ size_t iVar = 0;
TCollection_AsciiString aVar, aReplacedVar;
for(Standard_Integer i=aFirstParam;i <= aTotalNbParams;i++) {
//Replace first parameter (bettwen '(' character and first ',' character)
aStartPos = aCommand.Location(i-1, COMMA, 1, aCommand.Length()) + 2;
aEndPos = aCommand.Location(i, COMMA, 1, aCommand.Length());
}
+ if (aStartPos == 0 || aEndPos == 0)
+ continue;
if( aCommand.Value( aStartPos ) == O_SQR_BRACKET )
aStartPos++;
if ( aStartPos == aEndPos )
continue; // PAL20889: for "[]"
- if(MYDEBUG)
- cout<<"aStartPos = "<<aStartPos<<", aEndPos = "<<aEndPos<<endl;
+ MESSAGE("aStartPos = " << aStartPos << ", aEndPos = " << aEndPos);
aVar = aCommand.SubString(aStartPos, aEndPos-1);
aVar.RightAdjust();
aVar.LeftAdjust();
- if(MYDEBUG)
- cout<<"Variable: '"<< aVar <<"'"<<endl;
+ MESSAGE("Variable: '" << aVar << "'");
// specific case for sketcher
if(aVar.Location( TCollection_AsciiString("Sketcher:"), 1, aVar.Length() ) != 0) {
aEndSectionPos = aVar.Length();
aSection = aVar.SubString(aStartSectionPos, aEndSectionPos-1);
- if(MYDEBUG)
- cout<<"aSection: "<<aSection<<endl;
+ MESSAGE("aSection: " << aSection);
Standard_Integer aNbParams = 1;
while( aSection.Location( aNbParams, ' ', 1, aSection.Length() ) )
else
aEndParamPos = aSection.Length() + 1;
- if(MYDEBUG)
- cout<<"aParamIndex: "<<aParamIndex<<" aStartParamPos: " <<aStartParamPos<<" aEndParamPos: "<<aEndParamPos<<endl;
+ MESSAGE("aParamIndex: " << aParamIndex << " aStartParamPos: " << aStartParamPos << " aEndParamPos: " << aEndParamPos);
if ( aStartParamPos == aEndParamPos)
continue;
aParameter = aSection.SubString(aStartParamPos, aEndParamPos-1);
- if(MYDEBUG)
- cout<<"aParameter: "<<aParameter<<endl;
+ MESSAGE("aParameter: " << aParameter);
if(iVar >= aVariables.size())
continue;
aReplacedParameter.InsertAfter(aReplacedParameter.Length(),"'");
}
- if(MYDEBUG)
- cout<<"aSection before : "<<aSection<<endl;
+ MESSAGE("aSection before : " << aSection);
aSection.Remove(aStartParamPos, aEndParamPos - aStartParamPos);
aSection.Insert(aStartParamPos, aReplacedParameter);
- if(MYDEBUG)
- cout<<"aSection after : "<<aSection<<endl<<endl;
+ MESSAGE("aSection after : " << aSection << '\n');
iVar++;
}
- if(MYDEBUG)
- cout<<"aVar before : "<<aVar<<endl;
+
+ MESSAGE("aVar before : " << aVar);
+
aVar.Remove(aStartSectionPos, aEndSectionPos - aStartSectionPos);
aVar.Insert(aStartSectionPos, aSection);
- if(MYDEBUG)
- cout<<"aVar after : "<<aVar<<endl<<endl;
+
+ MESSAGE("aVar after : " << aVar << '\n');
}
- if(MYDEBUG)
- cout<<"aCommand before : "<<aCommand<<endl;
+ MESSAGE("aCommand before : " << aCommand);
aCommand.Remove(aStartPos, aEndPos - aStartPos);
aCommand.Insert(aStartPos, aVar);
- if(MYDEBUG)
- cout<<"aCommand after : "<<aCommand<<endl;
+ MESSAGE("aCommand after : " << aCommand);
break;
} // end of specific case for sketcher
aStates->IncrementState();
}
- if (MYDEBUG)
- cout<<"Command : "<<theCommand<<endl;
+ MESSAGE("Command after replacing of the variables: " << theCommand);
}
//=============================================================================
//=============================================================================
void ReplaceEntriesByNames (TCollection_AsciiString& theScript,
TSting2ObjDataMap& aEntry2ObjData,
- const bool theIsPublished,
+ const bool /*theIsPublished*/,
TColStd_SequenceOfAsciiString& theObjListToPublish,
Standard_Integer& objectCounter,
Resource_DataMapOfAsciiStringAsciiString& aNameToEntry)
if (!thePublished.count(theTag)) {
// This object is not published yet.
+ thePublished.insert(theTag);
+
std::map< int, TCollection_AsciiString >::const_iterator anIt =
theEntryToCmdMap.find(theTag);
TIntToListIntMap::const_iterator aRefIt = theMapRefs.find(theTag);
if (aRefIt != theMapRefs.end()) {
- // Recursively publish all references.
+ // Recursively publish all references.
std::list< int >::const_iterator aRefTagIt = aRefIt->second.begin();
for(; aRefTagIt != aRefIt->second.end(); ++aRefTagIt) {
// Add the object command.
aResult += anIt->second;
}
-
- thePublished.insert(theTag);
}
return aResult;
//================================================================================
TState ObjectStates::GetCurrectState() const
{
- if(_states.size() > _dumpstate)
+ if((int)_states.size() > _dumpstate)
return _states[_dumpstate];
return TState();
}