1 // Copyright (C) 2016-20xx CEA/DEN, EDF R&D -->
3 // File: ModelHighAPI_Dumper.cpp
4 // Created: 1 August 2016
5 // Author: Artem ZHIDKOV
7 //--------------------------------------------------------------------------------------
8 #include "ModelHighAPI_Dumper.h"
10 #include <GeomAPI_Pnt.h>
11 #include <GeomAPI_Dir.h>
13 #include <GeomDataAPI_Dir.h>
14 #include <GeomDataAPI_Point.h>
15 #include <GeomDataAPI_Point2D.h>
17 #include <ModelAPI_AttributeBoolean.h>
18 #include <ModelAPI_AttributeDouble.h>
19 #include <ModelAPI_AttributeIntArray.h>
20 #include <ModelAPI_AttributeInteger.h>
21 #include <ModelAPI_AttributeRefAttr.h>
22 #include <ModelAPI_AttributeRefAttrList.h>
23 #include <ModelAPI_AttributeReference.h>
24 #include <ModelAPI_AttributeRefList.h>
25 #include <ModelAPI_AttributeSelection.h>
26 #include <ModelAPI_AttributeSelectionList.h>
27 #include <ModelAPI_AttributeString.h>
28 #include <ModelAPI_CompositeFeature.h>
29 #include <ModelAPI_Document.h>
30 #include <ModelAPI_Entity.h>
31 #include <ModelAPI_Feature.h>
32 #include <ModelAPI_Result.h>
33 #include <ModelAPI_ResultPart.h>
35 #include <PartSetPlugin_Part.h>
37 #include <OSD_OpenFile.hxx>
41 static int gCompositeStackDepth = 0;
43 ModelHighAPI_Dumper* ModelHighAPI_Dumper::mySelf = 0;
45 ModelHighAPI_Dumper::ModelHighAPI_Dumper()
50 void ModelHighAPI_Dumper::setInstance(ModelHighAPI_Dumper* theDumper)
56 ModelHighAPI_Dumper* ModelHighAPI_Dumper::getInstance()
61 void ModelHighAPI_Dumper::clear(bool bufferOnly)
64 myDumpBuffer << std::setprecision(16);
70 myFullDump << std::setprecision(16);
74 myFeatureCount.clear();
75 while (!myEntitiesStack.empty())
76 myEntitiesStack.pop();
80 void ModelHighAPI_Dumper::clearNotDumped()
82 myNotDumpedEntities.clear();
85 const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity,
86 bool theSaveNotDumped,
87 bool theUseEntityName)
89 EntityNameMap::const_iterator aFound = myNames.find(theEntity);
90 if (aFound != myNames.end())
91 return aFound->second.first;
93 // entity is not found, store it
95 std::ostringstream aDefaultName;
96 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theEntity);
98 aName = aFeature->name();
99 const std::string& aKind = aFeature->getKind();
100 DocumentPtr aDoc = aFeature->document();
101 int& aNbFeatures = myFeatureCount[aDoc][aKind];
104 size_t anIndex = aName.find(aKind);
105 if (anIndex == 0 && aName[aKind.length()] == '_') { // name starts with "FeatureKind_"
106 std::string anIdStr = aName.substr(aKind.length() + 1);
107 int anId = std::stoi(anIdStr);
109 // Check number of already registered objects of such kind. Index of current object
110 // should be the same to identify feature's name as automatically generated.
111 if (aNbFeatures == anId) {
112 // name is not user-defined
117 // obtain default name for the feature
118 if (theUseEntityName)
119 aDefaultName << aName;
122 NbFeaturesMap::const_iterator aFIt = myFeatureCount.begin();
123 for (; aFIt != myFeatureCount.end(); ++aFIt) {
124 std::map<std::string, int>::const_iterator aFound = aFIt->second.find(aKind);
125 if (aFound != aFIt->second.end())
126 aFullIndex += aFound->second;
128 aDefaultName << aKind << "_" << aFullIndex;
131 // store names of results
132 saveResultNames(aFeature);
135 myNames[theEntity] = std::pair<std::string, std::string>(aDefaultName.str(), aName);
136 if (theSaveNotDumped)
137 myNotDumpedEntities.insert(theEntity);
138 return myNames[theEntity].first;
141 const std::string& ModelHighAPI_Dumper::parentName(const FeaturePtr& theEntity)
143 const std::set<AttributePtr>& aRefs = theEntity->data()->refsToMe();
144 std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
145 for (; aRefIt != aRefs.end(); ++aRefIt) {
146 CompositeFeaturePtr anOwner = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(
147 ModelAPI_Feature::feature((*aRefIt)->owner()));
149 return name(anOwner);
152 static const std::string DUMMY;
156 void ModelHighAPI_Dumper::saveResultNames(const FeaturePtr& theFeature)
158 std::string aFeatureName = theFeature->name();
159 const std::list<ResultPtr>& aResults = theFeature->results();
160 std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
161 for (int i = 1; aResIt != aResults.end(); ++aResIt, ++i) {
162 bool isUserDefined = true;
163 std::string aResName = (*aResIt)->data()->name();
164 size_t anIndex = aResName.find(aFeatureName);
166 std::string aSuffix = aResName.substr(aFeatureName.length());
167 if (aSuffix.empty() && i == 1) // first result may not constain index in the name
168 isUserDefined = false;
170 if (aSuffix[0] == '_' && std::stoi(aSuffix.substr(1)) == i)
171 isUserDefined = false;
175 myNames[*aResIt] = std::pair<std::string, std::string>(aResName,
176 isUserDefined ? aResName : std::string());
180 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_Document>& theDoc,
181 const std::string& theFileName)
183 // dump top level document feature
184 static const std::string aDocName("partSet");
185 myNames[theDoc] = std::pair<std::string, std::string>(aDocName, std::string());
186 *this << aDocName << " = model.moduleDocument()" << std::endl;
188 // dump subfeatures and store result to file
189 return process(theDoc) && exportTo(theFileName);
192 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_Document>& theDoc)
195 std::list<FeaturePtr> aFeatures = theDoc->allFeatures();
196 std::list<FeaturePtr>::const_iterator aFeatIt = aFeatures.begin();
197 // firstly, dump all parameters
198 for (; aFeatIt != aFeatures.end(); ++ aFeatIt)
199 dumpParameter(*aFeatIt);
200 // dump all other features
201 for (aFeatIt = aFeatures.begin(); aFeatIt != aFeatures.end(); ++aFeatIt) {
202 CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIt);
203 if (aCompFeat) // iteratively process composite features
204 isOk = process(aCompFeat) && isOk;
205 else if (!isDumped(*aFeatIt)) // dump common feature
206 dumpFeature(*aFeatIt);
211 bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_CompositeFeature>& theComposite, bool isForce)
213 // increase composite features stack
214 ++gCompositeStackDepth;
215 // dump composite itself
216 if (!isDumped(theComposite) || isForce)
217 dumpFeature(theComposite, isForce);
219 // sub-part is processed independently, because it provides separate document
220 if (theComposite->getKind() == PartSetPlugin_Part::ID()) {
221 // decrease composite features stack because we run into separate document
222 --gCompositeStackDepth;
224 ResultPartPtr aPartResult =
225 std::dynamic_pointer_cast<ModelAPI_ResultPart>(theComposite->lastResult());
228 DocumentPtr aSubDoc = aPartResult->partDoc();
231 // set name of document
232 const std::string& aPartName = myNames[theComposite].first;
233 std::string aDocName = aPartName + "_doc";
234 myNames[aSubDoc] = std::pair<std::string, std::string>(aDocName, std::string());
236 // dump document in a separate line
237 *this << aDocName << " = " << aPartName << ".document()" << std::endl;
238 // dump features in the document
239 return process(aSubDoc);
243 bool isOk = processSubs(theComposite);
244 // decrease composite features stack
245 --gCompositeStackDepth;
250 bool ModelHighAPI_Dumper::processSubs(const std::shared_ptr<ModelAPI_CompositeFeature>& theComposite,
254 // dump all sub-features;
255 int aNbSubs = theComposite->numberOfSubs();
256 for (int anIndex = 0; anIndex < aNbSubs; ++anIndex) {
257 FeaturePtr aFeature = theComposite->subFeature(anIndex);
258 if (isDumped(aFeature))
261 CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
262 if (aCompFeat) // iteratively process composite features
263 isOk = process(aCompFeat) && isOk;
265 dumpFeature(aFeature, true);
268 bool isDumpSetName = !myEntitiesStack.empty() &&
269 myEntitiesStack.top().myEntity == EntityPtr(theComposite);
270 bool isForceModelDo = isDumpSetName &&
271 (myEntitiesStack.top().myUserName || !myEntitiesStack.top().myResults.empty());
272 // It is necessary for the sketch to create its result when complete (command "model.do()").
273 // This option is set by flat theDumpModelDo.
274 // However, nested sketches are rebuilt by parent feature, so, they do not need
275 // explicit call of "model.do()". This will be controlled by the depth of the stack.
276 if (isForceModelDo || (theDumpModelDo && gCompositeStackDepth <= 1))
277 *this << "model.do()" << std::endl;
279 // dump "setName" for composite feature
285 bool ModelHighAPI_Dumper::exportTo(const std::string& theFileName)
288 OSD_OpenStream(aFile, theFileName.c_str(), std::ofstream::out);
289 if (!aFile.is_open())
293 for (ModulesMap::const_iterator aModIt = myModules.begin();
294 aModIt != myModules.end(); ++aModIt) {
295 aFile << "from " << aModIt->first << " import ";
296 if (aModIt->second.empty() ||
297 aModIt->second.find(std::string()) != aModIt->second.end())
298 aFile << "*"; // import whole module
300 // import specific features
301 std::set<std::string>::const_iterator anObjIt = aModIt->second.begin();
303 for (++anObjIt; anObjIt != aModIt->second.end(); ++anObjIt)
304 aFile << ", " << *anObjIt;
308 if (!myModules.empty())
311 aFile << "import model" << std::endl << std::endl;
312 aFile << "model.begin()" << std::endl;
314 // dump collected data
315 aFile << myFullDump.str();
316 aFile << myDumpBuffer.str();
319 aFile << "model.end()" << std::endl;
327 void ModelHighAPI_Dumper::importModule(const std::string& theModuleName,
328 const std::string& theObject)
330 myModules[theModuleName].insert(theObject);
333 void ModelHighAPI_Dumper::dumpEntitySetName()
335 const LastDumpedEntity& aLastDumped = myEntitiesStack.top();
337 // dump "setName" for the entity
338 if (aLastDumped.myUserName) {
339 std::pair<std::string, std::string> anEntityNames = myNames[aLastDumped.myEntity];
340 if (!anEntityNames.second.empty())
341 myDumpBuffer << anEntityNames.first << ".setName(\"" << anEntityNames.second << "\")" << std::endl;
342 anEntityNames.second.clear(); // don't dump "setName" for the entity twice
344 // dump "setName" for results
345 std::list<ResultPtr>::const_iterator aResIt = aLastDumped.myResults.begin();
346 std::list<ResultPtr>::const_iterator aResEnd = aLastDumped.myResults.end();
347 for (; aResIt != aResEnd; ++aResIt) {
349 std::pair<std::string, std::string> anEntityNames = myNames[*aResIt];
350 if (!anEntityNames.second.empty()) {
352 myDumpBuffer << ".setName(\"" << anEntityNames.second << "\")" << std::endl;
353 anEntityNames.second.clear(); // don't dump "setName" for the entity twice
356 if (!isDefaultColor(*aResIt)) {
357 AttributeIntArrayPtr aColor = (*aResIt)->data()->intArray(ModelAPI_Result::COLOR_ID());
358 if (aColor && aColor->isInitialized()) {
360 myDumpBuffer << ".setColor(" << aColor->value(0) << ", " << aColor->value(1)
361 << ", " << aColor->value(2) << ")" << std::endl;
366 myEntitiesStack.pop();
369 bool ModelHighAPI_Dumper::isDumped(const EntityPtr& theEntity) const
371 EntityNameMap::const_iterator aFound = myNames.find(theEntity);
372 return aFound != myNames.end();
375 bool ModelHighAPI_Dumper::isDefaultColor(const ResultPtr& theResult) const
377 AttributeIntArrayPtr aColor = theResult->data()->intArray(ModelAPI_Result::COLOR_ID());
378 if (!aColor || !aColor->isInitialized())
381 std::string aSection, aName, aDefault;
382 theResult->colorConfigInfo(aSection, aName, aDefault);
384 // dump current color
385 std::ostringstream aColorInfo;
386 aColorInfo << aColor->value(0) << "," << aColor->value(1) << "," << aColor->value(2);
388 return aDefault == aColorInfo.str();
391 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char theChar)
393 myDumpBuffer << theChar;
397 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char* theString)
399 myDumpBuffer << theString;
403 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::string& theString)
405 myDumpBuffer << theString;
409 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const bool theValue)
411 myDumpBuffer << (theValue ? "True" : "False");
415 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const int theValue)
417 myDumpBuffer << theValue;
421 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const double theValue)
423 myDumpBuffer << theValue;
427 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr<GeomAPI_Pnt>& thePoint)
429 importModule("GeomAPI", "GeomAPI_Pnt");
430 myDumpBuffer << "GeomAPI_Pnt(" << thePoint->x() << ", "
431 << thePoint->y() << ", " << thePoint->z() << ")";
435 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr<GeomAPI_Dir>& theDir)
437 importModule("GeomAPI", "GeomAPI_Dir");
438 myDumpBuffer << "GeomAPI_Dir(" << theDir->x() << ", "
439 << theDir->y() << ", " << theDir->z() << ")";
443 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
444 const std::shared_ptr<GeomDataAPI_Dir>& theDir)
446 myDumpBuffer << theDir->x() << ", " << theDir->y() << ", " << theDir->z();
450 static void dumpArray(std::ostringstream& theOutput, int theSize,
451 double* theValues, std::string* theTexts)
453 for (int i = 0; i < theSize; ++i) {
456 if (theTexts[i].empty())
457 theOutput << theValues[i];
459 theOutput << "\"" << theTexts[i] << "\"";
463 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
464 const std::shared_ptr<GeomDataAPI_Point>& thePoint)
466 static const int aSize = 3;
467 double aValues[aSize] = {thePoint->x(), thePoint->y(), thePoint->z()};
468 std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY(), thePoint->textZ()};
469 dumpArray(myDumpBuffer, aSize, aValues, aTexts);
473 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
474 const std::shared_ptr<GeomDataAPI_Point2D>& thePoint)
476 static const int aSize = 2;
477 double aValues[aSize] = {thePoint->x(), thePoint->y()};
478 std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY()};
479 dumpArray(myDumpBuffer, aSize, aValues, aTexts);
483 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
484 const std::shared_ptr<ModelAPI_AttributeBoolean>& theAttrBool)
486 myDumpBuffer << (theAttrBool->value() ? "True" : "False");
490 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
491 const std::shared_ptr<ModelAPI_AttributeInteger>& theAttrInt)
493 std::string aText = theAttrInt->text();
495 myDumpBuffer << theAttrInt->value();
497 myDumpBuffer << "\"" << aText << "\"";
501 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
502 const std::shared_ptr<ModelAPI_AttributeDouble>& theAttrReal)
504 std::string aText = theAttrReal->text();
506 myDumpBuffer << theAttrReal->value();
508 myDumpBuffer << "\"" << aText << "\"";
512 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
513 const std::shared_ptr<ModelAPI_AttributeString>& theAttrStr)
515 myDumpBuffer << "\"" << theAttrStr->value() << "\"";
519 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const FeaturePtr& theEntity)
521 myDumpBuffer << name(theEntity);
523 bool isUserDefinedName = !myNames[theEntity].second.empty();
524 // store results if they have user-defined names or colors
525 std::list<ResultPtr> aResultsWithNameOrColor;
526 const std::list<ResultPtr>& aResults = theEntity->results();
527 std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
528 for (; aResIt != aResults.end(); ++aResIt)
529 if (!myNames[*aResIt].second.empty() || !isDefaultColor(*aResIt))
530 aResultsWithNameOrColor.push_back(*aResIt);
531 // store just dumped entity to stack
532 myEntitiesStack.push(LastDumpedEntity(theEntity, isUserDefinedName, aResultsWithNameOrColor));
534 // remove entity from the list of not dumped items
535 myNotDumpedEntities.erase(theEntity);
539 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ResultPtr& theResult)
541 FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);
543 std::list<ResultPtr> aResults = aFeature->results();
544 for(std::list<ResultPtr>::const_iterator anIt = aResults.cbegin(); anIt != aResults.cend(); ++anIt, ++anIndex) {
545 if(theResult->isSame(*anIt)) {
549 myDumpBuffer << name(aFeature) << ".result()[" << anIndex << "]";
553 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ObjectPtr& theObject)
555 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
557 myDumpBuffer << name(aFeature);
561 ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
570 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const AttributePtr& theAttr)
572 FeaturePtr anOwner = ModelAPI_Feature::feature(theAttr->owner());
573 myDumpBuffer << name(anOwner) << "." << attributeGetter(anOwner, theAttr->id()) << "()";
577 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
578 const std::shared_ptr<ModelAPI_AttributeRefAttr>& theRefAttr)
580 if (theRefAttr->isObject())
581 *this << theRefAttr->object();
583 *this << theRefAttr->attr();
587 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
588 const std::shared_ptr<ModelAPI_AttributeRefAttrList>& theRefAttrList)
591 std::list<std::pair<ObjectPtr, AttributePtr> > aList = theRefAttrList->list();
592 bool isAdded = false;
593 std::list<std::pair<ObjectPtr, AttributePtr> >::const_iterator anIt = aList.begin();
594 for (; anIt != aList.end(); ++anIt) {
596 myDumpBuffer << ", ";
600 *this << anIt->first;
601 else if (anIt->second)
602 * this << anIt->second;
608 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
609 const std::shared_ptr<ModelAPI_AttributeReference>& theReference)
611 *this << theReference->value();
615 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
616 const std::shared_ptr<ModelAPI_AttributeRefList>& theRefList)
618 static const int aThreshold = 2;
619 // if number of elements in the list if greater than a threshold,
620 // dump it in a separate line with specific name
621 std::string aDumped = myDumpBuffer.str();
622 if (aDumped.empty() || theRefList->size() <= aThreshold) {
624 std::list<ObjectPtr> aList = theRefList->list();
625 bool isAdded = false;
626 std::list<ObjectPtr>::const_iterator anIt = aList.begin();
627 for (; anIt != aList.end(); ++anIt) {
629 myDumpBuffer << ", ";
637 // clear buffer and store list "as is"
638 myDumpBuffer.str("");
640 // save buffer and clear it again
641 std::string aDumpedList = myDumpBuffer.str();
642 myDumpBuffer.str("");
643 // obtain name of list
644 FeaturePtr anOwner = ModelAPI_Feature::feature(theRefList->owner());
645 std::string aListName = name(anOwner) + "_objects";
646 // store all previous data
647 myDumpBuffer << aListName << " = " << aDumpedList << std::endl
648 << aDumped << aListName;
653 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
654 const std::shared_ptr<ModelAPI_AttributeSelection>& theAttrSelect)
656 myDumpBuffer << "model.selection(";
658 if(!theAttrSelect->isInitialized()) {
663 GeomShapePtr aShape = theAttrSelect->value();
665 aShape = theAttrSelect->context()->shape();
673 myDumpBuffer << "\"" << aShape->shapeTypeStr() << "\", \"" << theAttrSelect->namingName() << "\")";
677 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
678 const std::shared_ptr<ModelAPI_AttributeSelectionList>& theAttrSelList)
683 std::string aShapeTypeStr;
685 bool isAdded = false;
687 for(int anIndex = 0; anIndex < theAttrSelList->size(); ++anIndex) {
688 AttributeSelectionPtr anAttribute = theAttrSelList->value(anIndex);
689 aShape = anAttribute->value();
691 aShape = anAttribute->context()->shape();
699 myDumpBuffer << ", ";
703 myDumpBuffer << "model.selection(\"" << aShape->shapeTypeStr() << "\", \"" << anAttribute->namingName() << "\")";
712 ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper,
713 std::basic_ostream<char>& (*theEndl)(std::basic_ostream<char>&))
715 theDumper.myDumpBuffer << theEndl;
717 if (!theDumper.myEntitiesStack.empty()) {
718 // Name for composite feature is dumped when all sub-entities are dumped
719 // (see method ModelHighAPI_Dumper::processSubs).
720 const ModelHighAPI_Dumper::LastDumpedEntity& aLastDumped = theDumper.myEntitiesStack.top();
721 CompositeFeaturePtr aComposite =
722 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aLastDumped.myEntity);
724 theDumper.dumpEntitySetName();
727 // store all not-dumped entities first
728 std::set<EntityPtr> aNotDumped = theDumper.myNotDumpedEntities;
729 std::string aBufCopy = theDumper.myDumpBuffer.str();
730 theDumper.clear(true);
731 std::set<EntityPtr>::const_iterator anIt = aNotDumped.begin();
732 for (; anIt != aNotDumped.end(); ++anIt) {
733 // if the feature is composite, dump it with all subs
734 CompositeFeaturePtr aCompFeat =
735 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*anIt);
737 theDumper.process(aCompFeat, true);
739 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
740 theDumper.dumpFeature(aFeature, true);
744 // avoid multiple empty lines
745 size_t anInd = std::string::npos;
746 while ((anInd = aBufCopy.find("\n\n\n")) != std::string::npos)
747 aBufCopy.erase(anInd, 1);
748 // then store currently dumped string
749 theDumper.myFullDump << aBufCopy;