From c9beae7ef329a0c09419ae04f277b2ffc0f83037 Mon Sep 17 00:00:00 2001 From: WandererFan Date: Mon, 23 Sep 2024 11:40:05 -0400 Subject: [PATCH] [TD] Fix win file spec backslash (fix #16646) (#16689) * [TD]add method to clean win filespecs - '\' in strings passed to Python as filespecs is interpreted as an escape of the following character. - replace '\' with '/' * [TD]remove '\' from filespecs before use --- src/Mod/TechDraw/App/DrawUtil.cpp | 12 ++++++++++++ src/Mod/TechDraw/App/DrawUtil.h | 2 ++ src/Mod/TechDraw/Gui/Command.cpp | 19 +++++++++++++------ src/Mod/TechDraw/Gui/CommandDecorate.cpp | 4 +++- src/Mod/TechDraw/Gui/PagePrinter.cpp | 17 ++++++++++++----- src/Mod/TechDraw/Gui/TaskActiveView.cpp | 9 ++++----- src/Mod/TechDraw/Gui/TaskGeomHatch.cpp | 6 +++++- src/Mod/TechDraw/Gui/TaskHatch.cpp | 9 +++++++-- 8 files changed, 58 insertions(+), 20 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawUtil.cpp b/src/Mod/TechDraw/App/DrawUtil.cpp index ed9a047200..e6c97702c2 100644 --- a/src/Mod/TechDraw/App/DrawUtil.cpp +++ b/src/Mod/TechDraw/App/DrawUtil.cpp @@ -1899,6 +1899,18 @@ bool DrawUtil::isCenterLine(App::DocumentObject* owner, std::string element) return false; } +//! convert a filespec (string) containing '\' to only use '/'. +//! prevents situation where '\' is interpreted as an escape of the next character in Python +//! commands. +std::string DrawUtil::cleanFilespecBackslash(const std::string& filespec) +{ + std::string forwardSlash{"/"}; + boost::regex rxBackslash("\\\\"); //this rx really means match to a single '\' + std::string noBackslash = boost::regex_replace(filespec, rxBackslash, forwardSlash); + return noBackslash; +} + + //============================ // various debugging routines. void DrawUtil::dumpVertexes(const char* text, const TopoDS_Shape& s) diff --git a/src/Mod/TechDraw/App/DrawUtil.h b/src/Mod/TechDraw/App/DrawUtil.h index c2cb7e3a10..bea3539b95 100644 --- a/src/Mod/TechDraw/App/DrawUtil.h +++ b/src/Mod/TechDraw/App/DrawUtil.h @@ -277,6 +277,8 @@ public: static bool isWithinRange(double actualAngleIn, double targetAngleIn, double allowableError); + static std::string cleanFilespecBackslash(const std::string& filespec); + //debugging routines static void dumpVertexes(const char* text, const TopoDS_Shape& s); diff --git a/src/Mod/TechDraw/Gui/Command.cpp b/src/Mod/TechDraw/Gui/Command.cpp index 87ef3d3bf6..3ae16501c4 100644 --- a/src/Mod/TechDraw/Gui/Command.cpp +++ b/src/Mod/TechDraw/Gui/Command.cpp @@ -94,6 +94,7 @@ std::pair viewDirection(); class Vertex; using namespace TechDrawGui; using namespace TechDraw; +using DU = DrawUtil; //=========================================================================== // TechDraw_PageDefault @@ -137,7 +138,8 @@ void CmdTechDrawPageDefault::activated(int iMsg) svgTemplate->translateLabel("DrawSVGTemplate", "Template", svgTemplate->getNameInDocument()); page->Template.setValue(svgTemplate); - svgTemplate->Template.setValue(templateFileName.toStdString()); + auto filespec = DU::cleanFilespecBackslash(Base::Tools::toStdString(templateFileName)); + svgTemplate->Template.setValue(filespec); updateActive(); commitCommand(); @@ -207,7 +209,8 @@ void CmdTechDrawPageTemplate::activated(int iMsg) svgTemplate->translateLabel("DrawSVGTemplate", "Template", svgTemplate->getNameInDocument()); page->Template.setValue(svgTemplate); - svgTemplate->Template.setValue(templateFileName.toStdString()); + auto filespec = DU::cleanFilespecBackslash(Base::Tools::toStdString(templateFileName)); + svgTemplate->Template.setValue(filespec); updateActive(); commitCommand(); @@ -448,8 +451,9 @@ void CmdTechDrawView::activated(int iMsg) || filename.endsWith(QString::fromLatin1(".svgz"), Qt::CaseInsensitive)) { std::string FeatName = getUniqueObjectName("Symbol"); filename = Base::Tools::escapeEncodeFilename(filename); + auto filespec = DU::cleanFilespecBackslash(Base::Tools::toStdString(filename)); openCommand(QT_TRANSLATE_NOOP("Command", "Create Symbol")); - doCommand(Doc, "f = open(\"%s\", 'r')", (const char*)filename.toUtf8()); + doCommand(Doc, "f = open(\"%s\", 'r')", filespec.c_str()); doCommand(Doc, "svg = f.read()"); doCommand(Doc, "f.close()"); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewSymbol', '%s')", @@ -463,11 +467,12 @@ void CmdTechDrawView::activated(int iMsg) else { std::string FeatName = getUniqueObjectName("Image"); filename = Base::Tools::escapeEncodeFilename(filename); + auto filespec = DU::cleanFilespecBackslash(Base::Tools::toStdString(filename)); openCommand(QT_TRANSLATE_NOOP("Command", "Create Image")); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewImage', '%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.translateLabel('DrawViewImage', 'Image', '%s')", FeatName.c_str(), FeatName.c_str()); - doCommand(Doc, "App.activeDocument().%s.ImageFile = '%s'", FeatName.c_str(), filename.toUtf8().constData()); + doCommand(Doc, "App.activeDocument().%s.ImageFile = '%s'", FeatName.c_str(), filespec.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); updateActive(); commitCommand(); @@ -1541,8 +1546,9 @@ void CmdTechDrawSymbol::activated(int iMsg) if (!filename.isEmpty()) { std::string FeatName = getUniqueObjectName("Symbol"); filename = Base::Tools::escapeEncodeFilename(filename); + auto filespec = DU::cleanFilespecBackslash(Base::Tools::toStdString(filename)); openCommand(QT_TRANSLATE_NOOP("Command", "Create Symbol")); - doCommand(Doc, "f = open(\"%s\", 'r')", (const char*)filename.toUtf8()); + doCommand(Doc, "f = open(\"%s\", 'r')", (const char*)filespec.c_str()); doCommand(Doc, "svg = f.read()"); doCommand(Doc, "f.close()"); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewSymbol', '%s')", @@ -1853,8 +1859,9 @@ void CmdTechDrawExportPageDXF::activated(int iMsg) openCommand(QT_TRANSLATE_NOOP("Command", "Save page to DXF")); doCommand(Doc, "import TechDraw"); fileName = Base::Tools::escapeEncodeFilename(fileName); + auto filespec = DU::cleanFilespecBackslash(Base::Tools::toStdString(fileName)); doCommand(Doc, "TechDraw.writeDXFPage(App.activeDocument().%s, u\"%s\")", PageName.c_str(), - (const char*)fileName.toUtf8()); + filespec.c_str()); commitCommand(); } diff --git a/src/Mod/TechDraw/Gui/CommandDecorate.cpp b/src/Mod/TechDraw/Gui/CommandDecorate.cpp index a78615f150..f60c5bbd1d 100644 --- a/src/Mod/TechDraw/Gui/CommandDecorate.cpp +++ b/src/Mod/TechDraw/Gui/CommandDecorate.cpp @@ -57,6 +57,7 @@ using namespace TechDrawGui; using namespace TechDraw; +using DU = DrawUtil; //internal functions bool _checkSelectionHatch(Gui::Command* cmd); @@ -266,11 +267,12 @@ void CmdTechDrawImage::activated(int iMsg) std::string FeatName = getUniqueObjectName("Image"); fileName = Base::Tools::escapeEncodeFilename(fileName); + auto filespec = DU::cleanFilespecBackslash(Base::Tools::toStdString(fileName)); openCommand(QT_TRANSLATE_NOOP("Command", "Create Image")); doCommand(Doc, "App.activeDocument().addObject('TechDraw::DrawViewImage', '%s')", FeatName.c_str()); doCommand(Doc, "App.activeDocument().%s.translateLabel('DrawViewImage', 'Image', '%s')", FeatName.c_str(), FeatName.c_str()); - doCommand(Doc, "App.activeDocument().%s.ImageFile = '%s'", FeatName.c_str(), fileName.toUtf8().constData()); + doCommand(Doc, "App.activeDocument().%s.ImageFile = '%s'", FeatName.c_str(), filespec.c_str()); doCommand(Doc, "App.activeDocument().%s.addView(App.activeDocument().%s)", PageName.c_str(), FeatName.c_str()); updateActive(); commitCommand(); diff --git a/src/Mod/TechDraw/Gui/PagePrinter.cpp b/src/Mod/TechDraw/Gui/PagePrinter.cpp index cb1dc293f6..208195d129 100644 --- a/src/Mod/TechDraw/Gui/PagePrinter.cpp +++ b/src/Mod/TechDraw/Gui/PagePrinter.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include "PagePrinter.h" @@ -58,6 +59,7 @@ using namespace TechDrawGui; using namespace TechDraw; +using DU = DrawUtil; constexpr double A4Heightmm = 297.0; constexpr double A4Widthmm = 210.0; @@ -148,7 +150,9 @@ void PagePrinter::printPdf(std::string file) } // set up the pdfwriter - QString outputFile = QString::fromUtf8(file.data(), file.size()); + auto filespec = Base::Tools::escapeEncodeFilename(file); + filespec = DU::cleanFilespecBackslash(file); + QString outputFile = Base::Tools::fromStdString(filespec); QPdfWriter pdfWriter(outputFile); QPageLayout pageLayout = pdfWriter.pageLayout(); auto marginsdb = pageLayout.margins(QPageLayout::Millimeter); @@ -375,22 +379,25 @@ void PagePrinter::saveSVG(std::string file) Base::Console().Warning("PagePrinter - no file specified\n"); return; } - QString filename = QString::fromUtf8(file.data(), file.size()); + auto filespec = Base::Tools::escapeEncodeFilename(file); + filespec = DU::cleanFilespecBackslash(file); + QString filename = Base::Tools::fromStdString(filespec); if (m_scene) { m_scene->saveSvg(filename); } } -void PagePrinter::saveDXF(std::string fileName) +void PagePrinter::saveDXF(std::string inFileName) { TechDraw::DrawPage* page = m_vpPage->getDrawPage(); std::string PageName = page->getNameInDocument(); - fileName = Base::Tools::escapeEncodeFilename(fileName); + auto filespec = Base::Tools::escapeEncodeFilename(inFileName); + filespec = DU::cleanFilespecBackslash(filespec); Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Save page to dxf")); Gui::Command::doCommand(Gui::Command::Doc, "import TechDraw"); Gui::Command::doCommand(Gui::Command::Doc, "TechDraw.writeDXFPage(App.activeDocument().%s, u\"%s\")", - PageName.c_str(), (const char*)fileName.c_str()); + PageName.c_str(), filespec.c_str()); Gui::Command::commitCommand(); } diff --git a/src/Mod/TechDraw/Gui/TaskActiveView.cpp b/src/Mod/TechDraw/Gui/TaskActiveView.cpp index 75147a4d14..9ef1d05a03 100644 --- a/src/Mod/TechDraw/Gui/TaskActiveView.cpp +++ b/src/Mod/TechDraw/Gui/TaskActiveView.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include "TaskActiveView.h" #include "ui_TaskActiveView.h" @@ -51,6 +52,7 @@ using namespace Gui; using namespace TechDraw; using namespace TechDrawGui; +using DU = DrawUtil; constexpr int SXGAWidth{1280}; constexpr int SXGAHeight{1024}; @@ -207,12 +209,9 @@ TechDraw::DrawViewImage* TaskActiveView::createActiveView() Base::Console().Error("ActiveView could not save file: %s\n", fileSpec.c_str()); } - //backslashes in windows fileSpec upsets python - std::regex rxBackslash("\\\\"); //this rx really means match to a single '\' - std::string noBackslash = std::regex_replace(tempName, rxBackslash, "/"); - + tempName = DU::cleanFilespecBackslash(tempName); Command::doCommand(Command::Doc, "App.getDocument('%s').%s.ImageFile = '%s'", - documentName.c_str(), imageName.c_str(), noBackslash.c_str()); + documentName.c_str(), imageName.c_str(), tempName.c_str()); Command::doCommand(Command::Doc, "App.getDocument('%s').%s.Width = %.5f", documentName.c_str(), imageName.c_str(), ui->qsbWidth->rawValue()); Command::doCommand(Command::Doc, "App.getDocument('%s').%s.Height = %.5f", documentName.c_str(), diff --git a/src/Mod/TechDraw/Gui/TaskGeomHatch.cpp b/src/Mod/TechDraw/Gui/TaskGeomHatch.cpp index 89b68fa7d0..9c4c540ce4 100644 --- a/src/Mod/TechDraw/Gui/TaskGeomHatch.cpp +++ b/src/Mod/TechDraw/Gui/TaskGeomHatch.cpp @@ -27,12 +27,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include "TaskGeomHatch.h" #include "ui_TaskGeomHatch.h" @@ -42,6 +44,7 @@ using namespace Gui; using namespace TechDraw; using namespace TechDrawGui; +using DU = DrawUtil; TaskGeomHatch::TaskGeomHatch(TechDraw::DrawGeomHatch* inHatch, TechDrawGui::ViewProviderGeomHatch* inVp, bool mode) : ui(new Ui_TaskGeomHatch), @@ -91,7 +94,8 @@ void TaskGeomHatch::initUi() void TaskGeomHatch::onFileChanged() { - m_file = ui->fcFile->fileName().toUtf8().constData(); + auto filespec = Base::Tools::toStdString(ui->fcFile->fileName()); + m_file = DU::cleanFilespecBackslash(filespec); std::vector names = PATLineSpec::getPatternList(m_file); QStringList qsNames = listToQ(names); ui->cbName->clear(); diff --git a/src/Mod/TechDraw/Gui/TaskHatch.cpp b/src/Mod/TechDraw/Gui/TaskHatch.cpp index 71280a0555..7466b0309a 100644 --- a/src/Mod/TechDraw/Gui/TaskHatch.cpp +++ b/src/Mod/TechDraw/Gui/TaskHatch.cpp @@ -48,6 +48,7 @@ using namespace Gui; using namespace TechDraw; using namespace TechDrawGui; +using DU = DrawUtil; //ctor for creation TaskHatch::TaskHatch(TechDraw::DrawViewPart* inDvp, std::vector subs) : @@ -208,9 +209,11 @@ void TaskHatch::createHatch() m_hatch = static_cast(doc->getObject(FeatName.c_str())); m_hatch->Source.setValue(m_dvp, m_subs); + auto filespec = Base::Tools::toStdString(ui->fcFile->fileName()); + filespec = DU::cleanFilespecBackslash(filespec); Command::doCommand(Command::Doc, "App.activeDocument().%s.HatchPattern = '%s'", FeatName.c_str(), - Base::Tools::toStdString(ui->fcFile->fileName()).c_str()); + filespec.c_str()); //view provider properties Gui::ViewProvider* vp = Gui::Application::Instance->getDocument(doc)->getViewProvider(m_hatch); @@ -236,9 +239,11 @@ void TaskHatch::updateHatch() Command::openCommand(QT_TRANSLATE_NOOP("Command", "Update Hatch")); + auto filespec = Base::Tools::toStdString(ui->fcFile->fileName()); + filespec = DU::cleanFilespecBackslash(filespec); Command::doCommand(Command::Doc, "App.activeDocument().%s.HatchPattern = '%s'", FeatName.c_str(), - Base::Tools::toStdString(ui->fcFile->fileName()).c_str()); + filespec.c_str()); App::Color ac; ac.setValue(ui->ccColor->color());