diff --git a/src/Base/Parameter.cpp b/src/Base/Parameter.cpp index bfab1492fb..046e516d15 100644 --- a/src/Base/Parameter.cpp +++ b/src/Base/Parameter.cpp @@ -81,7 +81,7 @@ using namespace Base; //************************************************************************** //************************************************************************** -// privat classes declaration: +// private classes declaration: // - DOMTreeErrorReporter // - StrX // - DOMPrintFilter @@ -195,12 +195,12 @@ class DOMPrintErrorHandler : public DOMErrorHandler { public: - DOMPrintErrorHandler() {}; - ~DOMPrintErrorHandler() {}; + DOMPrintErrorHandler() {} + ~DOMPrintErrorHandler() {} /** @name The error handler interface */ bool handleError(const DOMError& domError); - void resetErrors() {}; + void resetErrors() {} private : /* Unimplemented constructors and operators */ @@ -391,10 +391,10 @@ std::vector > ParameterGrp::GetGroups(void) pcTemp = FindElement(_pGroupNode,"FCParamGroup"); while (pcTemp) { - Name = StrX( ((DOMElement*)pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); + Name = StrX(static_cast(pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); // already created? if (!(rParamGrp=_GroupMap[Name]).isValid()) { - rParamGrp = Base::Reference (new ParameterGrp(((DOMElement*)pcTemp),Name.c_str())); + rParamGrp = Base::Reference (new ParameterGrp(static_cast(pcTemp),Name.c_str())); _GroupMap[Name] = rParamGrp; } vrParamGrp.push_back( rParamGrp ); @@ -443,10 +443,12 @@ void ParameterGrp::SetBool(const char* Name, bool bValue) { // find or create the Element DOMElement *pcElem = FindOrCreateElement(_pGroupNode,"FCBool",Name); - // and set the value - pcElem->setAttribute(XStr("Value").unicodeForm(), XStr(bValue?"1":"0").unicodeForm()); - // trigger observer - Notify(Name); + if (pcElem) { + // and set the value + pcElem->setAttribute(XStr("Value").unicodeForm(), XStr(bValue?"1":"0").unicodeForm()); + // trigger observer + Notify(Name); + } } std::vector ParameterGrp::GetBools(const char * sFilter) const @@ -457,10 +459,10 @@ std::vector ParameterGrp::GetBools(const char * sFilter) const pcTemp = FindElement(_pGroupNode,"FCBool"); while ( pcTemp) { - Name = StrX( ((DOMElement*)pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); + Name = StrX(static_cast(pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); // check on filter condition if (sFilter == NULL || Name.find(sFilter)!= std::string::npos) { - if (strcmp(StrX(((DOMElement*)pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str(),"1")) + if (strcmp(StrX(static_cast(pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str(),"1")) vrValues.push_back(false); else vrValues.push_back(true); @@ -479,10 +481,10 @@ std::vector > ParameterGrp::GetBoolMap(const char * pcTemp = FindElement(_pGroupNode,"FCBool"); while ( pcTemp) { - Name = StrX( ((DOMElement*)pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); + Name = StrX(static_cast(pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); // check on filter condition if (sFilter == NULL || Name.find(sFilter)!= std::string::npos) { - if (strcmp(StrX(((DOMElement*)pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str(),"1")) + if (strcmp(StrX(static_cast(pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str(),"1")) vrValues.push_back(std::make_pair(Name, false)); else vrValues.push_back(std::make_pair(Name, true)); @@ -508,11 +510,13 @@ void ParameterGrp::SetInt(const char* Name, long lValue) char cBuf[256]; // find or create the Element DOMElement *pcElem = FindOrCreateElement(_pGroupNode,"FCInt",Name); - // and set the value - sprintf(cBuf,"%li",lValue); - pcElem->setAttribute(XStr("Value").unicodeForm(), XStr(cBuf).unicodeForm()); - // trigger observer - Notify(Name); + if (pcElem) { + // and set the value + sprintf(cBuf,"%li",lValue); + pcElem->setAttribute(XStr("Value").unicodeForm(), XStr(cBuf).unicodeForm()); + // trigger observer + Notify(Name); + } } std::vector ParameterGrp::GetInts(const char * sFilter) const @@ -523,10 +527,10 @@ std::vector ParameterGrp::GetInts(const char * sFilter) const pcTemp = FindElement(_pGroupNode,"FCInt") ; while ( pcTemp ) { - Name = StrX( ((DOMElement*)pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); + Name = StrX(static_cast(pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); // check on filter condition if (sFilter == NULL || Name.find(sFilter)!= std::string::npos) { - vrValues.push_back( atol (StrX(((DOMElement*)pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str()) ); + vrValues.push_back(atol(StrX(static_cast(pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str()) ); } pcTemp = FindNextElement(pcTemp,"FCInt") ; } @@ -542,11 +546,11 @@ std::vector > ParameterGrp::GetIntMap(const char * s pcTemp = FindElement(_pGroupNode,"FCInt") ; while ( pcTemp ) { - Name = StrX( ((DOMElement*)pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); + Name = StrX(static_cast(pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); // check on filter condition if (sFilter == NULL || Name.find(sFilter)!= std::string::npos) { vrValues.push_back(std::make_pair(Name, - ( atol (StrX(((DOMElement*)pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str())))); + ( atol (StrX(static_cast(pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str())))); } pcTemp = FindNextElement(pcTemp,"FCInt") ; } @@ -569,11 +573,13 @@ void ParameterGrp::SetUnsigned(const char* Name, unsigned long lValue) char cBuf[256]; // find or create the Element DOMElement *pcElem = FindOrCreateElement(_pGroupNode,"FCUInt",Name); - // and set the value - sprintf(cBuf,"%lu",lValue); - pcElem->setAttribute(XStr("Value").unicodeForm(), XStr(cBuf).unicodeForm()); - // trigger observer - Notify(Name); + if (pcElem) { + // and set the value + sprintf(cBuf,"%lu",lValue); + pcElem->setAttribute(XStr("Value").unicodeForm(), XStr(cBuf).unicodeForm()); + // trigger observer + Notify(Name); + } } std::vector ParameterGrp::GetUnsigneds(const char * sFilter) const @@ -584,10 +590,10 @@ std::vector ParameterGrp::GetUnsigneds(const char * sFilter) cons pcTemp = FindElement(_pGroupNode,"FCUInt"); while ( pcTemp ) { - Name = StrX( ((DOMElement*)pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); + Name = StrX(static_cast(pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); // check on filter condition if (sFilter == NULL || Name.find(sFilter)!= std::string::npos) { - vrValues.push_back( strtoul (StrX(((DOMElement*)pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str(),0,10) ); + vrValues.push_back( strtoul (StrX(static_cast(pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str(),0,10) ); } pcTemp = FindNextElement(pcTemp,"FCUInt") ; } @@ -603,11 +609,11 @@ std::vector > ParameterGrp::GetUnsignedMap( pcTemp = FindElement(_pGroupNode,"FCUInt"); while ( pcTemp ) { - Name = StrX( ((DOMElement*)pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); + Name = StrX(static_cast(pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); // check on filter condition if (sFilter == NULL || Name.find(sFilter)!= std::string::npos) { vrValues.push_back(std::make_pair(Name, - ( strtoul (StrX(((DOMElement*)pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str(),0,10) ))); + ( strtoul (StrX(static_cast(pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str(),0,10) ))); } pcTemp = FindNextElement(pcTemp,"FCUInt"); } @@ -630,11 +636,13 @@ void ParameterGrp::SetFloat(const char* Name, double dValue) char cBuf[256]; // find or create the Element DOMElement *pcElem = FindOrCreateElement(_pGroupNode,"FCFloat",Name); - // and set the value - sprintf(cBuf,"%.12f",dValue); // use %.12f instead of %f to handle values < 1.0e-6 - pcElem->setAttribute(XStr("Value").unicodeForm(), XStr(cBuf).unicodeForm()); - // trigger observer - Notify(Name); + if (pcElem) { + // and set the value + sprintf(cBuf,"%.12f",dValue); // use %.12f instead of %f to handle values < 1.0e-6 + pcElem->setAttribute(XStr("Value").unicodeForm(), XStr(cBuf).unicodeForm()); + // trigger observer + Notify(Name); + } } std::vector ParameterGrp::GetFloats(const char * sFilter) const @@ -645,10 +653,10 @@ std::vector ParameterGrp::GetFloats(const char * sFilter) const pcTemp = FindElement(_pGroupNode,"FCFloat") ; while ( pcTemp ) { - Name = StrX( ((DOMElement*)pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); + Name = StrX(static_cast(pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); // check on filter condition if (sFilter == NULL || Name.find(sFilter)!= std::string::npos) { - vrValues.push_back( atof (StrX(((DOMElement*)pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str()) ); + vrValues.push_back( atof (StrX(static_cast(pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str()) ); } pcTemp = FindNextElement(pcTemp,"FCFloat"); } @@ -664,11 +672,11 @@ std::vector > ParameterGrp::GetFloatMap(const char pcTemp = FindElement(_pGroupNode,"FCFloat") ; while ( pcTemp ) { - Name = StrX( ((DOMElement*)pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); + Name = StrX(static_cast(pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); // check on filter condition if (sFilter == NULL || Name.find(sFilter)!= std::string::npos) { vrValues.push_back(std::make_pair(Name, - ( atof (StrX(((DOMElement*)pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str())))); + ( atof (StrX(static_cast(pcTemp)->getAttribute(XStr("Value").unicodeForm())).c_str())))); } pcTemp = FindNextElement(pcTemp,"FCFloat"); } @@ -694,19 +702,20 @@ void ParameterGrp::SetASCII(const char* Name, const char *sValue) { // find or create the Element DOMElement *pcElem = FindOrCreateElement(_pGroupNode,"FCText",Name); - // and set the value - DOMNode *pcElem2 = pcElem->getFirstChild(); - if (!pcElem2) { - XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *pDocument = _pGroupNode->getOwnerDocument(); - DOMText *pText = pDocument->createTextNode(XUTF8Str(sValue).unicodeForm()); - pcElem->appendChild(pText); + if (pcElem) { + // and set the value + DOMNode *pcElem2 = pcElem->getFirstChild(); + if (!pcElem2) { + XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *pDocument = _pGroupNode->getOwnerDocument(); + DOMText *pText = pDocument->createTextNode(XUTF8Str(sValue).unicodeForm()); + pcElem->appendChild(pText); + } + else { + pcElem2->setNodeValue(XUTF8Str(sValue).unicodeForm()); + } + // trigger observer + Notify(Name); } - else { - pcElem2->setNodeValue(XUTF8Str(sValue).unicodeForm()); - } - // trigger observer - Notify(Name); - } std::string ParameterGrp::GetASCII(const char* Name, const char * pPreset) const @@ -739,7 +748,7 @@ std::vector ParameterGrp::GetASCIIs(const char * sFilter) const pcTemp = FindElement(_pGroupNode,"FCText"); while ( pcTemp ) { - Name = StrXUTF8( ((DOMElement*)pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); + Name = StrXUTF8(static_cast(pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); // check on filter condition if (sFilter == NULL || Name.find(sFilter)!= std::string::npos) { // retrieve the text element @@ -761,7 +770,7 @@ std::vector > ParameterGrp::GetASCIIMap(const pcTemp = FindElement(_pGroupNode,"FCText"); while ( pcTemp) { - Name = StrXUTF8( ((DOMElement*)pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); + Name = StrXUTF8(static_cast(pcTemp)->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str(); // check on filter condition if (sFilter == NULL || Name.find(sFilter)!= std::string::npos) { // retrieve the text element @@ -778,22 +787,6 @@ std::vector > ParameterGrp::GetASCIIMap(const //************************************************************************** // Access methods -void ParameterGrp::RemoveGrp(const char* Name) -{ - // remove group handle - _GroupMap.erase(Name); - - // check if Element in group - DOMElement *pcElem = FindElement(_pGroupNode,"FCParamGroup",Name); - // if not return - if (!pcElem) - return; - else - _pGroupNode->removeChild(pcElem); - // trigger observer - Notify(Name); -} - void ParameterGrp::RemoveASCII(const char* Name) { // check if Element in group @@ -801,11 +794,12 @@ void ParameterGrp::RemoveASCII(const char* Name) // if not return if (!pcElem) return; - else - _pGroupNode->removeChild(pcElem); + + DOMNode* node = _pGroupNode->removeChild(pcElem); + node->release(); + // trigger observer Notify(Name); - } void ParameterGrp::RemoveBool(const char* Name) @@ -815,8 +809,9 @@ void ParameterGrp::RemoveBool(const char* Name) // if not return if (!pcElem) return; - else - _pGroupNode->removeChild(pcElem); + + DOMNode* node = _pGroupNode->removeChild(pcElem); + node->release(); // trigger observer Notify(Name); @@ -842,8 +837,9 @@ void ParameterGrp::RemoveFloat(const char* Name) // if not return if (!pcElem) return; - else - _pGroupNode->removeChild(pcElem); + + DOMNode* node = _pGroupNode->removeChild(pcElem); + node->release(); // trigger observer Notify(Name); @@ -856,8 +852,9 @@ void ParameterGrp::RemoveInt(const char* Name) // if not return if (!pcElem) return; - else - _pGroupNode->removeChild(pcElem); + + DOMNode* node = _pGroupNode->removeChild(pcElem); + node->release(); // trigger observer Notify(Name); @@ -870,8 +867,38 @@ void ParameterGrp::RemoveUnsigned(const char* Name) // if not return if (!pcElem) return; - else - _pGroupNode->removeChild(pcElem); + + DOMNode* node = _pGroupNode->removeChild(pcElem); + node->release(); + + // trigger observer + Notify(Name); +} + +void ParameterGrp::RemoveGrp(const char* Name) +{ + auto it = _GroupMap.find(Name); + if (it == _GroupMap.end()) + return; + + // if this or any of its children is referenced by an observer + // it cannot be deleted + if (!it->second->ShouldRemove()) { + it->second->Clear(); + } + else { + // check if Element in group + DOMElement *pcElem = FindElement(_pGroupNode,"FCParamGroup",Name); + // if not return + if (!pcElem) + return; + + // remove group handle + _GroupMap.erase(Name); + + DOMNode* node = _pGroupNode->removeChild(pcElem); + node->release(); + } // trigger observer Notify(Name); @@ -882,34 +909,63 @@ void ParameterGrp::Clear(void) std::vector vecNodes; // checking on references - std::map >::iterator It1; - for (It1 = _GroupMap.begin();It1!=_GroupMap.end();++It1) - if (It1->second.getRefCount() > 1) - Console().Warning("ParameterGrp::Clear(): Group clear with active references"); - // remove group handles - _GroupMap.clear(); + std::vector removeGrp; + for (auto it = _GroupMap.begin();it!=_GroupMap.end();++it) { + // If a group is referenced by some observer then do not remove it + // but clear it + if (!it->second->ShouldRemove()) { + it->second->Clear(); + } + else { + removeGrp.push_back(it->first); + } + } - // searching all nodes - for (DOMNode *clChild = _pGroupNode->getFirstChild(); clChild != 0; clChild = clChild->getNextSibling()) { - vecNodes.push_back(clChild); + // remove group handles + for (auto it : removeGrp) { + auto pos = _GroupMap.find(it); + vecNodes.push_back(pos->second->_pGroupNode); + _GroupMap.erase(pos->first); + } + + // searching all non-group nodes + for (DOMNode *child = _pGroupNode->getFirstChild(); child != 0; child = child->getNextSibling()) { + if (XMLString::compareString(child->getNodeName(), XStr("FCParamGroup").unicodeForm()) != 0) + vecNodes.push_back(child); } // deleting the nodes - DOMNode* pcTemp; - for (std::vector::iterator It=vecNodes.begin();It!=vecNodes.end();++It) { - pcTemp = _pGroupNode->removeChild(*It); - //delete pcTemp; - pcTemp->release(); + for (auto it = vecNodes.begin(); it != vecNodes.end(); ++it) { + DOMNode *child = _pGroupNode->removeChild(*it); + child->release(); } + // trigger observer - Notify(0); + Notify(""); } //************************************************************************** // Access methods +bool ParameterGrp::ShouldRemove() const +{ + if (this->getRefCount() > 1) + return false; + for (auto it : _GroupMap) { + bool ok = it.second->ShouldRemove(); + if (!ok) + return false; + } + return true; +} + XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *ParameterGrp::FindElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *Start, const char* Type, const char* Name) const { + if (XMLString::compareString(Start->getNodeName(), XStr("FCParamGroup").unicodeForm()) != 0 && + XMLString::compareString(Start->getNodeName(), XStr("FCParameters").unicodeForm()) != 0) { + Base::Console().Warning("FindElement: %s cannot have the element %s of type %s\n", StrX(Start->getNodeName()).c_str(), Name, Type); + return nullptr; + } for (DOMNode *clChild = Start->getFirstChild(); clChild != 0; clChild = clChild->getNextSibling()) { if (clChild->getNodeType() == DOMNode::ELEMENT_NODE) { // the right node Type @@ -917,10 +973,10 @@ XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *ParameterGrp::FindElement(XERCES_CPP_ if (clChild->getAttributes()->getLength() > 0) { if (Name) { if (!strcmp(Name,StrX(clChild->getAttributes()->getNamedItem(XStr("Name").unicodeForm())->getNodeValue()).c_str())) - return (DOMElement*)clChild; + return static_cast(clChild); } else - return (DOMElement*)clChild; + return static_cast(clChild); } } @@ -932,13 +988,14 @@ XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *ParameterGrp::FindElement(XERCES_CPP_ XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *ParameterGrp::FindNextElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *Prev, const char* Type) const { DOMNode *clChild = Prev; - if (!clChild) return 0l; + if (!clChild) + return nullptr; while ((clChild = clChild->getNextSibling())!=0) { if (clChild->getNodeType() == DOMNode::ELEMENT_NODE) { // the right node Type if (!strcmp(Type,StrX(clChild->getNodeName()).c_str())) { - return (DOMElement*)clChild; + return static_cast(clChild); } } } @@ -949,15 +1006,21 @@ XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *ParameterGrp::FindOrCreateElement(XER { // first try to find it DOMElement *pcElem = FindElement(Start,Type,Name); + if (pcElem) + return pcElem; - if (!pcElem) { - XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *pDocument = _pGroupNode->getOwnerDocument(); - - pcElem = pDocument->createElement(XStr(Type).unicodeForm()); - pcElem-> setAttribute(XStr("Name").unicodeForm(), XStr(Name).unicodeForm()); - Start->appendChild(pcElem); + if (XMLString::compareString(Start->getNodeName(), XStr("FCParamGroup").unicodeForm()) != 0 && + XMLString::compareString(Start->getNodeName(), XStr("FCParameters").unicodeForm()) != 0) { + Base::Console().Warning("FindOrCreateElement: %s cannot have the element %s of type %s\n", StrX(Start->getNodeName()).c_str(), Name, Type); + return nullptr; } + XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *pDocument = _pGroupNode->getOwnerDocument(); + + pcElem = pDocument->createElement(XStr(Type).unicodeForm()); + pcElem-> setAttribute(XStr("Name").unicodeForm(), XStr(Name).unicodeForm()); + Start->appendChild(pcElem); + return pcElem; } @@ -1189,7 +1252,7 @@ int ParameterManager::LoadDocument(const char* sFileName) try { #if defined (FC_OS_WIN32) - LocalFileInputSource inputSource((XMLCh*)file.toStdWString().c_str()); + LocalFileInputSource inputSource(reinterpret_cast(file.toStdWString().c_str())); #else LocalFileInputSource inputSource(XStr(file.filePath().c_str()).unicodeForm()); #endif @@ -1286,7 +1349,7 @@ void ParameterManager::SaveDocument(const char* sFileName) const // to a file once it receives any thing from the serializer. // #if defined (FC_OS_WIN32) - XMLFormatTarget *myFormTarget = new LocalFileFormatTarget ((XMLCh*)file.toStdWString().c_str()); + XMLFormatTarget *myFormTarget = new LocalFileFormatTarget (reinterpret_cast(file.toStdWString().c_str())); #else XMLFormatTarget *myFormTarget = new LocalFileFormatTarget (file.filePath().c_str()); #endif @@ -1378,7 +1441,7 @@ void ParameterManager::SaveDocument(XMLFormatTarget* pFormatTarget) const XMLCh tempStr[100]; XMLString::transcode("LS", tempStr, 99); DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr); - DOMLSSerializer *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer(); + DOMLSSerializer *theSerializer = static_cast(impl)->createLSSerializer(); // set user specified end of line sequence and output encoding theSerializer->setNewLine(gMyEOLSequence); @@ -1388,7 +1451,7 @@ void ParameterManager::SaveDocument(XMLFormatTarget* pFormatTarget) const // do the serialization through DOMWriter::writeNode(); // if (_pDocument) { - DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput(); + DOMLSOutput *theOutput = static_cast(impl)->createLSOutput(); theOutput->setEncoding(gOutputEncoding); if (gUseFilter) { @@ -1443,7 +1506,7 @@ void ParameterManager::CreateDocument(void) // creating the node for the root group DOMElement* rootElem = _pDocument->getDocumentElement(); _pGroupNode = _pDocument->createElement(XStr("FCParamGroup").unicodeForm()); - ((DOMElement*)_pGroupNode)->setAttribute(XStr("Name").unicodeForm(), XStr("Root").unicodeForm()); + static_cast(_pGroupNode)->setAttribute(XStr("Name").unicodeForm(), XStr("Root").unicodeForm()); rootElem->appendChild(_pGroupNode); } diff --git a/src/Base/Parameter.h b/src/Base/Parameter.h index 081580a918..7a7b7ee67a 100644 --- a/src/Base/Parameter.h +++ b/src/Base/Parameter.h @@ -22,6 +22,13 @@ * Juergen Riegel 2002 * ***************************************************************************/ + /** + * \file Parameter.h + * \brief The classes defined here are used to interface with the XML-based + * FreeCAD config files: user.cfg and system.cfg files. It can parse, get, + * and store the parameters/configurations for the user's preferences. + * 3rd party Xerces-C++ XML parser is used to parse and write the XML. + */ #ifndef BASE__PARAMETER_H #define BASE__PARAMETER_H @@ -93,7 +100,7 @@ class ParameterManager; * kind of preferences and so on. * @see ParameterManager */ -class BaseExport ParameterGrp : public Base::Handled,public Base::Subject +class BaseExport ParameterGrp : public Base::Handled,public Base::Subject { @@ -236,6 +243,7 @@ protected: ~ParameterGrp(); /// helper function for GetGroup Base::Reference _GetGroup(const char* Name); + bool ShouldRemove() const; XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *FindNextElement(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *Prev, const char* Type) const; diff --git a/src/Base/swigpyrun.inl b/src/Base/swigpyrun.inl index 0eedaaa87a..65bba62db3 100644 --- a/src/Base/swigpyrun.inl +++ b/src/Base/swigpyrun.inl @@ -72,7 +72,7 @@ void cleanupSWIG_T(const char* TypeName) PyObject *module, *dict; PyInterpreterState *interp = PyThreadState_GET()->interp; - PyObject *modules = interp->modules; + PyObject *modules = PyImport_GetModuleDict(); module = PyDict_GetItemString(modules, "__builtin__"); if (module != NULL && PyModule_Check(module)) { dict = PyModule_GetDict(module); diff --git a/src/Gui/DlgParameterImp.cpp b/src/Gui/DlgParameterImp.cpp index eb09ecc2e7..61c7fd9048 100644 --- a/src/Gui/DlgParameterImp.cpp +++ b/src/Gui/DlgParameterImp.cpp @@ -404,16 +404,21 @@ void ParameterGroup::onDeleteSelectedItem() QTreeWidgetItem* sel = currentItem(); if (isItemSelected(sel) && sel->parent()) { - if ( QMessageBox::question(this, tr("Remove group"), tr("Do really want to remove this parameter group?"), + if ( QMessageBox::question(this, tr("Remove group"), tr("Do you really want to remove this parameter group?"), QMessageBox::Yes, QMessageBox::No|QMessageBox::Default|QMessageBox::Escape) == QMessageBox::Yes ) { QTreeWidgetItem* parent = sel->parent(); int index = parent->indexOfChild(sel); parent->takeChild(index); - ParameterGroupItem* para = static_cast(parent); - para->_hcGrp->RemoveGrp(sel->text(0).toLatin1()); + + std::string groupName = sel->text(0).toStdString(); + // must delete the tree item here because it and its children still + // hold a reference to the parameter group delete sel; + + ParameterGroupItem* para = static_cast(parent); + para->_hcGrp->RemoveGrp(groupName.c_str()); } } } diff --git a/src/Mod/Cloud/App/AppCloud.cpp b/src/Mod/Cloud/App/AppCloud.cpp index 3d18fa8e88..254b53c735 100644 --- a/src/Mod/Cloud/App/AppCloud.cpp +++ b/src/Mod/Cloud/App/AppCloud.cpp @@ -28,6 +28,8 @@ #include #include +#include + #include #include @@ -193,31 +195,15 @@ void Cloud::CloudWriter::checkText(DOMText* text) { void Cloud::CloudWriter::createBucket() { - printf("CREATING BUCKET %s\n", this->Bucket); - struct timeval tv; - struct tm *tm; - char date_formatted[256]; - char StringToSign[1024]; - unsigned char *digest; - + struct Cloud::AmzData *RequestData; CURL *curl; CURLcode res; struct data_buffer curl_buffer; -#if defined(FC_OS_WIN32) -#else - gettimeofday(&tv,NULL); - tm = localtime(&tv.tv_sec); - strftime(date_formatted,256,"%a, %d %b %Y %T %z", tm); -#endif - - // CHANGEME - sprintf(StringToSign,"PUT\n\napplication/xml\n%s\n/%s/", date_formatted, this->Bucket); - - // We have to use HMAC encoding and SHA1 - digest=HMAC(EVP_sha1(),this->SecretKey,strlen(this->SecretKey), - (const unsigned char *)&StringToSign,strlen(StringToSign),NULL,NULL); + char path[1024]; + sprintf(path, "/%s/", this->Bucket); + RequestData = Cloud::ComputeDigestAmzS3v2("PUT", "application/xml", path, this->SecretKey, NULL, 0); // Let's build the Header and call to curl curl_global_init(CURL_GLOBAL_ALL); @@ -225,27 +211,22 @@ void Cloud::CloudWriter::createBucket() if ( curl ) { struct curl_slist *chunk = NULL; - char header_data[1024]; + char Url[256]; // Let's build our own header std::string strUrl(this->Url); eraseSubStr(strUrl,"http://"); eraseSubStr(strUrl,"https://"); - sprintf(header_data,"Host: %s", strUrl.c_str()); - chunk = curl_slist_append(chunk, header_data); - sprintf(header_data,"Date: %s", date_formatted); - chunk = curl_slist_append(chunk, header_data); - chunk = curl_slist_append(chunk, "Content-Type: application/xml"); - std::string digest_str; - digest_str=Base::base64_encode(digest,strlen((const char *)digest)); - sprintf(header_data,"Authorization: AWS %s:%s", this->AccessKey, - digest_str.c_str()); - chunk = curl_slist_append(chunk, header_data); + chunk = Cloud::BuildHeaderAmzS3v2( strUrl.c_str(), this->TcpPort, this->AccessKey, RequestData); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); -// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - sprintf(header_data,"%s:%s/%s/", this->Url,this->TcpPort, + + // Lets build the Url for our Curl call + + sprintf(Url,"%s:%s/%s/", this->Url,this->TcpPort, this->Bucket); - curl_easy_setopt(curl, CURLOPT_URL, header_data); + curl_easy_setopt(curl, CURLOPT_URL, Url); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); curl_easy_setopt(curl, CURLOPT_PUT, 1L); // curl read a file not a memory buffer (it shall be able to do it) @@ -266,13 +247,113 @@ void Cloud::CloudWriter::createBucket() } } -Cloud::CloudWriter::CloudWriter(const char* Url, const char* AccessKey, const char* SecretKey, const char* TcpPort, const char* Bucket) +struct Cloud::AmzData *Cloud::ComputeDigestAmzS3v2(char *operation, char *data_type, const char *target, const char *Secret, const char *ptr, long size) { + struct AmzData *returnData; struct timeval tv; struct tm *tm; char date_formatted[256]; - char StringToSign[1024]; - unsigned char *digest; + char StringToSign[1024]; + unsigned char *digest; + unsigned int HMACLength; + // Amazon S3 and Swift require the timezone to be define to GMT. + // As to simplify the conversion this is performed through the TZ + // environment variable and a call to localtime as to convert output of gettimeofday + returnData = ( struct Cloud::AmzData *) malloc(sizeof(struct Cloud::AmzData)); + + strcpy(returnData->ContentType, data_type); + +#if defined(FC_OS_WIN32) + _putenv("TZ=GMT"); +#else + setenv("TZ","GMT",1); +#endif + // We must check that the bucket exists or not. If not, we have to create it. + // We must request the bucketlist if we receive a 404 error. This means that it + // doesn't exist. The other option is that the content list is empty. + // This piece of code is the same as the Reader except we do not interpret it ! +#if defined(FC_OS_WIN32) +#else + gettimeofday(&tv,NULL); + tm = localtime(&tv.tv_sec); + strftime(date_formatted,256,"%a, %d %b %Y %T %z", tm); +#endif + returnData->MD5=NULL; + if ( strcmp(operation,"PUT") == 0 ) + { + if ( ptr != NULL ) + { + returnData->MD5=Cloud::MD5Sum(ptr,size); + sprintf(StringToSign,"%s\n%s\n%s\n%s\n%s", operation, returnData->MD5, data_type, date_formatted, target); + } + else + sprintf(StringToSign,"%s\n\n%s\n%s\n%s", operation, data_type, date_formatted, target); + } + else + sprintf(StringToSign,"%s\n\n%s\n%s\n%s", operation, data_type, date_formatted, target); + // We have to use HMAC encoding and SHA1 + digest=HMAC(EVP_sha1(),Secret,strlen(Secret), + (const unsigned char *)&StringToSign,strlen(StringToSign),NULL,&HMACLength); + returnData->digest = Base::base64_encode(digest,HMACLength); + strcpy(returnData->dateFormatted,date_formatted); + return returnData; + +} + +char *Cloud::MD5Sum(const char *ptr, long size) +{ + char *output; + std::string local; + unsigned char result[MD5_DIGEST_LENGTH]; + output=(char *)malloc(2*MD5_DIGEST_LENGTH*sizeof(char)+1); + MD5((unsigned char*) ptr, size, result); + local= Base::base64_encode(result,MD5_DIGEST_LENGTH); + strcpy(output,local.c_str()); + return(output); +} + +struct curl_slist *Cloud::BuildHeaderAmzS3v2(const char *Url, const char *TcpPort, const char *PublicKey, struct Cloud::AmzData *Data) +{ + char header_data[1024]; + struct curl_slist *chunk = NULL; + + // Build the Host: entry + + sprintf(header_data,"Host: %s:%s", Url, TcpPort); + chunk = curl_slist_append(chunk, header_data); + + // Build the Date entry + + sprintf(header_data,"Date: %s", Data->dateFormatted); + chunk = curl_slist_append(chunk, header_data); + + // Build the Content-Type entry + + sprintf(header_data,"Content-Type:%s", Data->ContentType); + chunk = curl_slist_append(chunk, header_data); + + // If ptr is not null we must compute the MD5-Sum as to validate later the ETag + // and add the MD5-Content: entry to the header + if ( Data->MD5 != NULL ) + { + sprintf(header_data,"Content-MD5: %s", Data->MD5); + chunk = curl_slist_append(chunk, header_data); + // We don't need it anymore we can free it + free((void *)Data->MD5); + } + + // build the Auth entry + + sprintf(header_data,"Authorization: AWS %s:%s", PublicKey, + Data->digest.c_str()); + chunk = curl_slist_append(chunk, header_data); + + return chunk; +} + +Cloud::CloudWriter::CloudWriter(const char* Url, const char* AccessKey, const char* SecretKey, const char* TcpPort, const char* Bucket) +{ + struct Cloud::AmzData *RequestData; CURL *curl; CURLcode res; @@ -284,58 +365,31 @@ Cloud::CloudWriter::CloudWriter(const char* Url, const char* AccessKey, const ch this->TcpPort=TcpPort; this->Bucket=Bucket; this->FileName=""; - // Amazon S3 and Swift require the timezone to be define to GMT. - // As to simplify the conversion this is performed through the TZ - // environment variable and a call to localtime as to convert output of gettimeofday -#if defined(FC_OS_WIN32) - _putenv("TZ=GMT"); -#else - setenv("TZ","GMT",1); -#endif - // We must check that the bucket exists or not. If not, we have to create it. - // We must request the bucketlist if we receive a 404 error. This means that it - // doesn't exist. The other option is that the content list is empty. - // This piece of code is the same as the Reader except we do not interpret it ! -#if defined(FC_OS_WIN32) -#else - gettimeofday(&tv,NULL); - tm = localtime(&tv.tv_sec); - strftime(date_formatted,256,"%a, %d %b %Y %T %z", tm); -#endif - - sprintf(StringToSign,"GET\n\napplication/xml\n%s\n/%s/", date_formatted, this->Bucket); - - // We have to use HMAC encoding and SHA1 - digest=HMAC(EVP_sha1(),this->SecretKey,strlen(this->SecretKey), - (const unsigned char *)&StringToSign,strlen(StringToSign),NULL,NULL); - + char path[1024]; + sprintf(path,"/%s/", this->Bucket); + RequestData = Cloud::ComputeDigestAmzS3v2("GET", "application/xml", path, this->SecretKey, NULL, 0); // Let's build the Header and call to curl curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); if ( curl ) { - struct curl_slist *chunk = NULL; - char header_data[1024]; // Let's build our own header + struct curl_slist *chunk = NULL; + char Url[256]; std::string strUrl(this->Url); eraseSubStr(strUrl,"http://"); eraseSubStr(strUrl,"https://"); - sprintf(header_data,"Host: %s:%s", strUrl.c_str(), - this->TcpPort); - chunk = curl_slist_append(chunk, header_data); - sprintf(header_data,"Date: %s", date_formatted); - chunk = curl_slist_append(chunk, header_data); - chunk = curl_slist_append(chunk, "Content-Type: application/xml"); - std::string digest_str; - digest_str=Base::base64_encode(digest,strlen((const char *)digest)); - sprintf(header_data,"Authorization: AWS %s:%s", this->AccessKey, - digest_str.c_str()); - chunk = curl_slist_append(chunk, header_data); + chunk = Cloud::BuildHeaderAmzS3v2( strUrl.c_str(), this->TcpPort, this->AccessKey, RequestData); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); - sprintf(header_data,"%s:%s/%s/", this->Url,this->TcpPort, + + // Lets build the Url for our Curl call + + sprintf(Url,"%s:%s/%s/", this->Url,this->TcpPort, this->Bucket); - curl_easy_setopt(curl, CURLOPT_URL, header_data); + curl_easy_setopt(curl, CURLOPT_URL, Url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s); // curl read a file not a memory buffer (it shall be able to do it) @@ -344,7 +398,8 @@ Cloud::CloudWriter::CloudWriter(const char* Url, const char* AccessKey, const ch fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); curl_easy_cleanup(curl); - + free( RequestData); + // Let's dump temporarly for debug purpose of s3v4 implementation std::stringstream input(s); @@ -458,11 +513,7 @@ Cloud::CloudReader::~CloudReader() Cloud::CloudReader::CloudReader(const char* Url, const char* AccessKey, const char* SecretKey, const char* TcpPort, const char* Bucket) { - struct timeval tv; - struct tm *tm; - char date_formatted[256]; - char StringToSign[1024]; - unsigned char *digest; + struct Cloud::AmzData *RequestData; CURL *curl; CURLcode res; @@ -475,58 +526,32 @@ Cloud::CloudReader::CloudReader(const char* Url, const char* AccessKey, const ch this->TcpPort=TcpPort; this->Bucket=Bucket; - // Amazon S3 and Swift require the timezone to be define to - // GMT. As to simplify the conversion this is performed through the TZ - // environment variable and a call to localtime as to convert output of gettimeofday -#if defined(FC_OS_WIN32) - _putenv("TZ=GMT"); -#else - setenv("TZ","GMT",1); -#endif + char path[1024]; + sprintf(path,"/%s/", this->Bucket); + RequestData = Cloud::ComputeDigestAmzS3v2("GET", "application/xml", path, this->SecretKey, NULL, 0); - // We must get the directory content - - -#if defined(FC_OS_WIN32) -#else - gettimeofday(&tv,NULL); - tm = localtime(&tv.tv_sec); - strftime(date_formatted,256,"%a, %d %b %Y %T %z", tm); -#endif - - sprintf(StringToSign,"GET\n\napplication/xml\n%s\n/%s/", date_formatted, this->Bucket); - - // We have to use HMAC encoding and SHA1 - digest=HMAC(EVP_sha1(),this->SecretKey,strlen(this->SecretKey), - (const unsigned char *)&StringToSign,strlen(StringToSign),NULL,NULL); // Let's build the Header and call to curl curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); if ( curl ) { + // Let's build our own header struct curl_slist *chunk = NULL; - char header_data[1024]; - // Let's build our own header - std::string strUrl(this->Url); + char Url[256]; + std::string strUrl(this->Url); eraseSubStr(strUrl,"http://"); eraseSubStr(strUrl,"https://"); - sprintf(header_data,"Host: %s:%s", strUrl.c_str(), - this->TcpPort); - chunk = curl_slist_append(chunk, header_data); - sprintf(header_data,"Date: %s", date_formatted); - chunk = curl_slist_append(chunk, header_data); - chunk = curl_slist_append(chunk, "Content-Type: application/xml"); - std::string digest_str; - digest_str=Base::base64_encode(digest,strlen((const char *)digest)); - sprintf(header_data,"Authorization: AWS %s:%s", this->AccessKey, - digest_str.c_str()); - chunk = curl_slist_append(chunk, header_data); + chunk = Cloud::BuildHeaderAmzS3v2( strUrl.c_str(), this->TcpPort, this->AccessKey, RequestData); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); - sprintf(header_data,"%s:%s/%s/", this->Url,this->TcpPort, + + sprintf(Url,"%s:%s/%s/", this->Url,this->TcpPort, this->Bucket); - curl_easy_setopt(curl, CURLOPT_URL, header_data); + curl_easy_setopt(curl, CURLOPT_URL, Url); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s); // curl read a file not a memory buffer (it shall be able to do it) @@ -564,31 +589,16 @@ Cloud::CloudReader::CloudReader(const char* Url, const char* AccessKey, const ch void Cloud::CloudReader::DownloadFile(Cloud::CloudReader::FileEntry *entry) { - struct timeval tv; - struct tm *tm; - char date_formatted[256]; - char StringToSign[1024]; - unsigned char *digest; + struct Cloud::AmzData *RequestData; CURL *curl; CURLcode res; std::string s; // We must get the directory content - - -#if defined(FC_OS_WIN32) -#else - gettimeofday(&tv,NULL); - tm = localtime(&tv.tv_sec); - strftime(date_formatted,256,"%a, %d %b %Y %T %z", tm); -#endif - - // CHANGEME - sprintf(StringToSign,"GET\n\napplication/octet-stream\n%s\n/%s/%s", date_formatted, this->Bucket, entry->FileName); - // We have to use HMAC encoding and SHA1 - digest=HMAC(EVP_sha1(),this->SecretKey,strlen(this->SecretKey), - (const unsigned char *)&StringToSign,strlen(StringToSign),NULL,NULL); + char path[1024]; + sprintf(path, "/%s/%s", this->Bucket, entry->FileName); + RequestData = Cloud::ComputeDigestAmzS3v2("GET", "application/octet-stream", path, this->SecretKey, NULL, 0); // Let's build the Header and call to curl curl_global_init(CURL_GLOBAL_ALL); @@ -596,26 +606,20 @@ void Cloud::CloudReader::DownloadFile(Cloud::CloudReader::FileEntry *entry) if ( curl ) { struct curl_slist *chunk = NULL; - char header_data[1024]; + char Url[256]; // Let's build our own header std::string strUrl(this->Url); eraseSubStr(strUrl,"http://"); eraseSubStr(strUrl,"https://"); - sprintf(header_data,"Host: %s:%s", strUrl.c_str(), - this->TcpPort); - chunk = curl_slist_append(chunk, header_data); - sprintf(header_data,"Date: %s", date_formatted); - chunk = curl_slist_append(chunk, header_data); - chunk = curl_slist_append(chunk, "Content-Type: application/octet-stream"); - std::string digest_str; - digest_str=Base::base64_encode(digest,strlen((const char *)digest)); - sprintf(header_data,"Authorization: AWS %s:%s", this->AccessKey, - digest_str.c_str()); - chunk = curl_slist_append(chunk, header_data); + + chunk = Cloud::BuildHeaderAmzS3v2( strUrl.c_str(), this->TcpPort, this->AccessKey, RequestData); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); - sprintf(header_data,"%s:%s/%s/%s", this->Url,this->TcpPort, - this->Bucket,entry->FileName); - curl_easy_setopt(curl, CURLOPT_URL, header_data); + + sprintf(Url,"%s:%s/%s/%s", this->Url,this->TcpPort, + this->Bucket, entry->FileName); + curl_easy_setopt(curl, CURLOPT_URL, Url); + // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s); @@ -696,31 +700,14 @@ bool Cloud::CloudWriter::shouldWrite(const std::string& , const Base::Persistenc void Cloud::CloudWriter::pushCloud(const char *FileName, const char *data, long size) { - struct timeval tv; - struct tm *tm; - char date_formatted[256]; - char StringToSign[1024]; - unsigned char *digest; - // char my_data[1024]="a que coucou"; - + struct Cloud::AmzData *RequestData; CURL *curl; CURLcode res; + struct data_buffer curl_buffer; - struct data_buffer curl_buffer; - -#if defined(FC_OS_WIN32) -#else - gettimeofday(&tv,NULL); - tm = localtime(&tv.tv_sec); - strftime(date_formatted,256,"%a, %d %b %Y %T %z", tm); -#endif - - // CHANGEME - sprintf(StringToSign,"PUT\n\napplication/octet-stream\n%s\n/%s/%s", date_formatted, this->Bucket, FileName); - - // We have to use HMAC encoding and SHA1 - digest=HMAC(EVP_sha1(),this->SecretKey,strlen(this->SecretKey), - (const unsigned char *)&StringToSign,strlen(StringToSign),NULL,NULL); + char path[1024]; + sprintf(path, "/%s/%s", this->Bucket, FileName); + RequestData = Cloud::ComputeDigestAmzS3v2("PUT", "application/octet-stream", path, this->SecretKey, data, size); // Let's build the Header and call to curl curl_global_init(CURL_GLOBAL_ALL); @@ -728,28 +715,26 @@ void Cloud::CloudWriter::pushCloud(const char *FileName, const char *data, long if ( curl ) { struct curl_slist *chunk = NULL; - char header_data[1024]; + char Url[256]; // Let's build our own header std::string strUrl(this->Url); eraseSubStr(strUrl,"http://"); eraseSubStr(strUrl,"https://"); - - sprintf(header_data,"Host: %s:%s", strUrl.c_str(), - this->TcpPort); - chunk = curl_slist_append(chunk, header_data); - sprintf(header_data,"Date: %s", date_formatted); - chunk = curl_slist_append(chunk, header_data); - chunk = curl_slist_append(chunk, "Content-Type: application/octet-stream"); - std::string digest_str; - digest_str=Base::base64_encode(digest,strlen((const char *)digest)); - sprintf(header_data,"Authorization: AWS %s:%s", this->AccessKey, - digest_str.c_str()); - chunk = curl_slist_append(chunk, header_data); + + + chunk = Cloud::BuildHeaderAmzS3v2( strUrl.c_str(), this->TcpPort, this->AccessKey, RequestData); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); -// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - sprintf(header_data,"%s:%s/%s/%s", this->Url,this->TcpPort, + + // Lets build the Url for our Curl call + + sprintf(Url,"%s:%s/%s/%s", this->Url,this->TcpPort, this->Bucket,FileName); - curl_easy_setopt(curl, CURLOPT_URL, header_data); + curl_easy_setopt(curl, CURLOPT_URL, Url); + + +// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); curl_easy_setopt(curl, CURLOPT_PUT, 1L); // curl read a file not a memory buffer (it shall be able to do it) diff --git a/src/Mod/Cloud/App/AppCloud.h b/src/Mod/Cloud/App/AppCloud.h index 1650d73425..b95dc6c136 100644 --- a/src/Mod/Cloud/App/AppCloud.h +++ b/src/Mod/Cloud/App/AppCloud.h @@ -47,8 +47,19 @@ XERCES_CPP_NAMESPACE_END namespace Cloud { +struct AmzData { + std::string digest; + char dateFormatted[256]; + char ContentType[256]; + char Host[256]; + char *MD5; +}; + void eraseSubStr(std::string & Str, const std::string & toErase); size_t CurlWrite_CallbackFunc_StdString(void *contents, size_t size, size_t nmemb, std::string *s); +struct AmzData *ComputeDigestAmzS3v2(char *operation, char *data_type, const char *target, const char *Secret, const char *ptr, long size); +struct curl_slist *BuildHeaderAmzS3v2(const char *Url, const char *TcpPort, const char *PublicKey, struct AmzData *Data); +char *MD5Sum(const char *ptr, long size); class CloudAppExport CloudReader { diff --git a/src/Mod/Import/App/dxf.cpp b/src/Mod/Import/App/dxf.cpp index c8ac9c12a3..abc8b09526 100644 --- a/src/Mod/Import/App/dxf.cpp +++ b/src/Mod/Import/App/dxf.cpp @@ -31,10 +31,16 @@ Base::Vector3d toVector3d(const double* a) CDxfWrite::CDxfWrite(const char* filepath) : //TODO: these should probably be parms in config file -m_entityHandle(0x300), -m_layerHandle(0x30), -m_blockHandle(0x210), -m_blkRecordHandle(0x110), +//handles: +//boilerplate 0 - A00 +//used by dxf.cpp A01 - FFFE +//ACAD HANDSEED FFFF + +m_handle(0xA00), //room for 2560 handles in boilerplate files +//m_entityHandle(0x300), //don't need special ranges for handles +//m_layerHandle(0x30), +//m_blockHandle(0x210), +//m_blkRecordHandle(0x110), m_polyOverride(false), m_layerName("none") { @@ -435,40 +441,53 @@ std::string CDxfWrite::getPlateFile(std::string fileSpec) return outString.str(); } -std::string CDxfWrite::getEntityHandle(void) +std::string CDxfWrite::getHandle(void) { - m_entityHandle++; + m_handle++; std::stringstream ss; ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); - ss << m_entityHandle; + ss << m_handle; return ss.str(); } +std::string CDxfWrite::getEntityHandle(void) +{ + return getHandle(); +// m_entityHandle++; +// std::stringstream ss; +// ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); +// ss << m_entityHandle; +// return ss.str(); +} + std::string CDxfWrite::getLayerHandle(void) { - m_layerHandle++; - std::stringstream ss; - ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); - ss << m_layerHandle; - return ss.str(); + return getHandle(); +// m_layerHandle++; +// std::stringstream ss; +// ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); +// ss << m_layerHandle; +// return ss.str(); } std::string CDxfWrite::getBlockHandle(void) { - m_blockHandle++; - std::stringstream ss; - ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); - ss << m_blockHandle; - return ss.str(); + return getHandle(); +// m_blockHandle++; +// std::stringstream ss; +// ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); +// ss << m_blockHandle; +// return ss.str(); } std::string CDxfWrite::getBlkRecordHandle(void) { - m_blkRecordHandle++; - std::stringstream ss; - ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); - ss << m_blkRecordHandle; - return ss.str(); + return getHandle(); +// m_blkRecordHandle++; +// std::stringstream ss; +// ss << std::uppercase << std::hex << std::setfill('0') << std::setw(2); +// ss << m_blkRecordHandle; +// return ss.str(); } void CDxfWrite::addBlockName(std::string b, std::string h) diff --git a/src/Mod/Import/App/dxf.h b/src/Mod/Import/App/dxf.h index 505c99a7ab..5de6bb7700 100644 --- a/src/Mod/Import/App/dxf.h +++ b/src/Mod/Import/App/dxf.h @@ -145,6 +145,7 @@ protected: //! copy boiler plate file std::string getPlateFile(std::string fileSpec); void setDataDir(std::string s) { m_dataDir = s; } + std::string getHandle(void); std::string getEntityHandle(void); std::string getLayerHandle(void); std::string getBlockHandle(void); @@ -152,6 +153,7 @@ protected: std::string m_optionSource; int m_version; + int m_handle; int m_entityHandle; int m_layerHandle; int m_blockHandle; diff --git a/src/Mod/Import/DxfPlate/header14.rub b/src/Mod/Import/DxfPlate/header14.rub index 5253db1285..a6cf3fa447 100644 --- a/src/Mod/Import/DxfPlate/header14.rub +++ b/src/Mod/Import/DxfPlate/header14.rub @@ -31,8 +31,24 @@ $CMLSTYLE 2 STANDARD 9 +$PEXTMAX + 10 +50 + 20 +50 + 30 +50 + 9 +$PEXTMIN + 10 +0 + 20 +0 + 30 +0 + 9 $HANDSEED 5 -FFF +FFFF 0 ENDSEC diff --git a/src/Mod/Import/DxfPlate/objects14.rub b/src/Mod/Import/DxfPlate/objects14.rub index 8313b799b7..e8e2adb95b 100644 --- a/src/Mod/Import/DxfPlate/objects14.rub +++ b/src/Mod/Import/DxfPlate/objects14.rub @@ -5,7 +5,7 @@ OBJECTS 0 DICTIONARY 5 -500 +F000 330 0 100 @@ -13,13 +13,13 @@ AcDbDictionary 3 ACAD_GROUP 350 -501 +F001 0 DICTIONARY 5 -501 +F001 330 -500 +F000 100 AcDbDictionary 0 diff --git a/src/Mod/Import/DxfPlate/tables214.rub b/src/Mod/Import/DxfPlate/tables214.rub index a3b91cb934..040b26821e 100644 --- a/src/Mod/Import/DxfPlate/tables214.rub +++ b/src/Mod/Import/DxfPlate/tables214.rub @@ -3,7 +3,7 @@ TABLE 2 STYLE 5 -60 +70 330 0 100 @@ -13,9 +13,9 @@ AcDbSymbolTable 0 STYLE 5 -61 +71 330 -60 +70 100 AcDbSymbolTableRecord 100 @@ -41,9 +41,9 @@ arial.ttf 0 STYLE 5 -62 +72 330 -60 +70 100 AcDbSymbolTableRecord 100 @@ -73,7 +73,7 @@ TABLE 2 VIEW 5 -63 +73 330 0 100 @@ -87,7 +87,7 @@ TABLE 2 UCS 5 -64 +74 330 0 100 @@ -101,7 +101,7 @@ TABLE 2 APPID 5 -65 +75 330 0 100 @@ -111,9 +111,9 @@ AcDbSymbolTable 0 APPID 5 -66 +76 330 -65 +75 100 AcDbSymbolTableRecord 100 @@ -125,9 +125,9 @@ ACAD 0 APPID 5 -67 +77 330 -65 +75 100 AcDbSymbolTableRecord 100 @@ -143,7 +143,7 @@ TABLE 2 DIMSTYLE 5 -68 +78 330 0 100 @@ -153,9 +153,9 @@ AcDbSymbolTable 0 DIMSTYLE 105 -69 +79 330 -68 +78 100 AcDbSymbolTableRecord 100 @@ -253,7 +253,7 @@ STANDARD 274 3 340 -61 +71 275 0 280 diff --git a/src/Mod/OpenSCAD/InitGui.py b/src/Mod/OpenSCAD/InitGui.py index 16335a0d0e..0a5d4db5f4 100644 --- a/src/Mod/OpenSCAD/InitGui.py +++ b/src/Mod/OpenSCAD/InitGui.py @@ -38,9 +38,11 @@ class OpenSCADWorkbench ( Workbench ): def __init__(self): self.__class__.Icon = FreeCAD.getResourceDir() + "Mod/OpenSCAD/Resources/icons/OpenSCADWorkbench.svg" self.__class__.MenuText = "OpenSCAD" - self.__class__.ToolTip = "OpenSCAD is an application for creating solid 3D CAD." + '\n' + - "FreeCAD utizes OpenSCAD's capability as a script-only based modeller that uses its own description language" + '\n' + - "Note: the Mesh workbench heavily uses the boolean operations of this workbench because they are quite robust" + self.__class__.ToolTip = ( + "OpenSCAD is an application for creating solid 3D CAD.\n" + "FreeCAD utizes OpenSCAD's capability as a script-only based modeller that uses its own description language\n" + "Note: the Mesh workbench heavily uses the boolean operations of this workbench because they are quite robust" + ) def Initialize(self): def QT_TRANSLATE_NOOP(scope, text): diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp index 2c0df20fe9..969250b500 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp @@ -538,21 +538,26 @@ void QGIViewDimension::updateDim() if ( vp == nullptr ) { return; } - + // QString labelText = QString::fromUtf8(dim->getFormatedValue().c_str()); //want this split into value and unit QString labelText = QString::fromUtf8(dim->getFormatedValue(1).c_str()); //just the number QString unitText = QString::fromUtf8(dim->getFormatedValue(2).c_str()); //just the unit - + QString arbText = QString::fromUtf8(dim->FormatSpec.getValue()); + QFont font = datumLabel->getFont(); font.setFamily(QString::fromUtf8(vp->Font.getValue())); font.setPixelSize(calculateFontPixelSize(vp->Fontsize.getValue())); datumLabel->setFont(font); prepareGeometryChange(); - datumLabel->setDimString(labelText); - datumLabel->setTolString(); - datumLabel->setUnitString(unitText); + if (dim->Arbitrary.getValue()) { + datumLabel->setDimString(arbText); + } else { + datumLabel->setDimString(labelText); + datumLabel->setTolString(); + datumLabel->setUnitString(unitText); + } datumLabel->setPosFromCenter(datumLabel->X(),datumLabel->Y()); datumLabel->setFramed(dim->TheoreticalExact.getValue()); diff --git a/src/Mod/Test/BaseTests.py b/src/Mod/Test/BaseTests.py index ba12d8a43b..ffc7cb364b 100644 --- a/src/Mod/Test/BaseTests.py +++ b/src/Mod/Test/BaseTests.py @@ -113,8 +113,8 @@ class ParameterTestCase(unittest.TestCase): self.failUnless(self.TestPar.HasGroup("44"),"Test on created group failed") # check on Deletion self.TestPar.RemGroup("44") - self.failUnless(not self.TestPar.HasGroup("44"),"Test on delete group failed") - Temp =0 + self.failUnless(self.TestPar.HasGroup("44"),"A referenced group must not be deleted") + Temp = 0 #check on special conditions def testInt(self): diff --git a/src/WindowsInstaller/README.md b/src/WindowsInstaller/README.md index f1bc9aa0ec..dda44646f6 100644 --- a/src/WindowsInstaller/README.md +++ b/src/WindowsInstaller/README.md @@ -20,14 +20,14 @@ To build the installer you can do the following: (You can alternatively get nsProcess from https://nsis.sourceforge.io/NsProcess_plugin) 7. Copy all FreeCAD files to the folder "~\FreeCAD" e.g. "C:\FreeCAD\Installer\FreeCAD" -8. If you use compiled FreeCAD using another MSVC version than MSVC 2015, copy +8. If you use compiled FreeCAD using another MSVC version than MSVC 2017, copy its distributable DLLs to the folder FILES_DEPS (see step 2). 9. Right-click on the file FreeCAD-installer.nsi and choose "Compile NSIS script" to compile the installer -10. The folder ~\MSVCRedist contains already all MSVC 2015 redistributable DLLs necessary - for FreeCAD. If another MSVC version was used to compile FreeCAD, replace the DLLs by +10. The folder ~\MSVCRedist contains already all MSVC 2017 x64 redistributable DLLs necessary + for FreeCAD 0.19dev. If another MSVC version was used to compile FreeCAD, replace the DLLs by the ones of the used MSVC. (They are usually available in the folder - C:\Program Files (x86)\MSVC2xxx\VC\redist) + C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Redist\MSVC) For test builds of the installer you can turn off the compression. This speeds up the build time for the installer a lot but increases its file size. The compression diff --git a/src/WindowsInstaller/Settings.nsh b/src/WindowsInstaller/Settings.nsh index c12ce26854..b4d66973cb 100644 --- a/src/WindowsInstaller/Settings.nsh +++ b/src/WindowsInstaller/Settings.nsh @@ -16,11 +16,12 @@ SetCompressor /SOLID lzma # Version number !define APP_VERSION_MAJOR 0 -!define APP_VERSION_MINOR 18 +!define APP_VERSION_MINOR 19 !define APP_VERSION_REVISION 0 -!define APP_VERSION_EMERGENCY "" # use "1" for an emergency release of FreeCAD otherwise "" +!define APP_VERSION_EMERGENCY "rev18542" # use "1" for an emergency release of FreeCAD otherwise "" + # alternatively you can use APP_VERSION_EMERGENCY for a custom suffix of the version number !define APP_EMERGENCY_DOT "" # use "." for an emergency release of FreeCAD otherwise "" -!define APP_VERSION_BUILD 10 # Start with 1 for the installer releases of each version +!define APP_VERSION_BUILD 1 # Start with 1 for the installer releases of each version !define APP_VERSION "${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}.${APP_VERSION_REVISION}${APP_EMERGENCY_DOT}${APP_VERSION_EMERGENCY}" # Version to display diff --git a/src/WindowsInstaller/include/declarations.nsh b/src/WindowsInstaller/include/declarations.nsh index 056e89a1cd..5b79a4bfb3 100644 --- a/src/WindowsInstaller/include/declarations.nsh +++ b/src/WindowsInstaller/include/declarations.nsh @@ -1,4 +1,4 @@ -/* +/* declaration.nsh Configuration and variables of FreeCAD installer @@ -32,8 +32,8 @@ Configuration and variables of FreeCAD installer !define APP_WIKI_INFO "${APP_NAME} Wiki" !define APP_COPYRIGHT "${APP_NAME} is Copyright © 2001-${COPYRIGHT_YEAR} by the ${APP_NAME} Team" -!define APP_RUN "bin\FreeCAD.exe" -!define BIN_FREECAD "FreeCAD.exe" +!define APP_RUN "bin\${APP_NAME}.exe" +!define BIN_FREECAD "${APP_NAME}.exe" !define APP_REGKEY "Software\${APP_NAME}${APP_SERIES_KEY}" # like "FreeCAD0180" !define APP_REGKEY_SETUP "${APP_REGKEY}\Setup" diff --git a/src/WindowsInstaller/include/init.nsh b/src/WindowsInstaller/include/init.nsh index 7d05feabfa..145a38d025 100644 --- a/src/WindowsInstaller/include/init.nsh +++ b/src/WindowsInstaller/include/init.nsh @@ -130,7 +130,10 @@ Function .onInit ${endif} ${next} - ${if} $OldVersionNumber > ${APP_SERIES_KEY} + # NSIS cannot handle numbers with leading zero, thus cut it off before comparing + StrCpy $1 $OldVersionNumber "" 1 + StrCpy $2 ${APP_SERIES_KEY} "" 1 + ${if} $1 > $2 # store the version number and reformat it temporarily for the error message StrCpy $R0 $OldVersionNumber StrCpy $OldVersionNumber $R5 diff --git a/src/WindowsInstaller/setup/configure.nsh b/src/WindowsInstaller/setup/configure.nsh index d91c8ca3b4..7b576fae4e 100644 --- a/src/WindowsInstaller/setup/configure.nsh +++ b/src/WindowsInstaller/setup/configure.nsh @@ -43,7 +43,7 @@ Section -InstallData WriteRegStr SHCTX ${APP_UNINST_KEY} "UninstallString" '"$INSTDIR\${SETUP_UNINSTALLER}"' WriteRegStr SHCTX ${APP_UNINST_KEY} "DisplayVersion" "${APP_VERSION}" - WriteRegStr SHCTX ${APP_UNINST_KEY} "DisplayIcon" "$INSTDIR\bin\FreeCAD.exe" + WriteRegStr SHCTX ${APP_UNINST_KEY} "DisplayIcon" "$INSTDIR\bin\${APP_NAME}.exe" WriteRegStr SHCTX ${APP_UNINST_KEY} "URLUpdateInfo" "${APP_WEBPAGE}" WriteRegStr SHCTX ${APP_UNINST_KEY} "URLInfoAbout" "https://www.freecadweb.org/" WriteRegStr SHCTX ${APP_UNINST_KEY} "Publisher" "${APP_NAME} Team" @@ -53,10 +53,15 @@ Section -InstallData WriteRegStr SHCTX ${APP_UNINST_KEY} "StartMenu" "$SMPROGRAMS\$StartmenuFolder" # if we install over an older existing version, remove the old uninstaller information - ${if} $OldVersionNumber < ${APP_SERIES_KEY} + # NSIS cannot handle numbers with leading zero, thus cut it off before comparing + StrCpy $1 $OldVersionNumber "" 1 + StrCpy $2 ${APP_SERIES_KEY} "" 1 + ${if} $1 < $2 DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}$OldVersionNumber" + DeleteRegKey SHCTX "SOFTWARE\${APP_NAME}$OldVersionNumber" # also delete in the case of an emergency release DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}$OldVersionNumber1" + DeleteRegKey SHCTX "SOFTWARE\${APP_NAME}$OldVersionNumber1" ${endif} SectionEnd diff --git a/src/WindowsInstaller/setup/install.nsh b/src/WindowsInstaller/setup/install.nsh index 3ba5ababce..cc186b4a25 100644 --- a/src/WindowsInstaller/setup/install.nsh +++ b/src/WindowsInstaller/setup/install.nsh @@ -15,7 +15,7 @@ Section -ProgramFiles SecProgramFiles # be installed directly to C:\programs - the uninstaller will then delete the whole # C:\programs directory StrCpy $String $INSTDIR - StrCpy $Search "FreeCAD" + StrCpy $Search ${APP_NAME} Call StrPoint # function from Utils.nsh ${if} $Pointer == "-1" StrCpy $INSTDIR "$INSTDIR\${APP_DIR}" @@ -43,6 +43,7 @@ Section -ProgramFiles SecProgramFiles File /r "${FILES_FREECAD}\Ext" File /r "${FILES_FREECAD}\lib" File /r "${FILES_FREECAD}\Mod" + File /r "${FILES_FREECAD}\resources" # Create uninstaller WriteUninstaller "$INSTDIR\${SETUP_UNINSTALLER}"