LCOV - code coverage report
Current view: top level - muse/framework/global/io - path.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 54.6 % 141 77
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #include "path.h"
      23              : 
      24              : #ifndef NO_QT_SUPPORT
      25              : #include <QDir>
      26              : #endif
      27              : 
      28              : #include "global/stringutils.h"
      29              : #include "fileinfo.h"
      30              : 
      31              : using namespace muse;
      32              : using namespace muse::io;
      33              : 
      34        14006 : path_t::path_t(const String& s)
      35        14006 :     : m_path(s.toStdString())
      36              : {
      37        14006 : }
      38              : 
      39         1254 : path_t::path_t(const std::string& s)
      40         1254 :     : m_path(s)
      41              : {
      42         1254 : }
      43              : 
      44          927 : path_t::path_t(std::string&& s)
      45          927 :     : m_path(std::move(s))
      46              : {
      47          927 : }
      48              : 
      49        22113 : path_t::path_t(const char* s)
      50        44226 :     : m_path(s ? s : "")
      51              : {
      52        22113 : }
      53              : 
      54         1501 : bool path_t::empty() const
      55              : {
      56         1501 :     return m_path.empty();
      57              : }
      58              : 
      59          576 : size_t path_t::size() const
      60              : {
      61          576 :     return m_path.size();
      62              : }
      63              : 
      64            4 : bool path_t::hasSuffix(const char* str) const
      65              : {
      66            4 :     return io::FileInfo::suffix(m_path).toLower() == str;
      67              : }
      68              : 
      69          362 : path_t path_t::appendingComponent(const path_t& other) const
      70              : {
      71          724 :     if ((!m_path.empty() && m_path.back() == '/')
      72          724 :         || (!other.m_path.empty() && other.m_path.front() == '/')) {
      73            0 :         return m_path + other.m_path;
      74              :     }
      75              : 
      76          362 :     return m_path + '/' + other.m_path;
      77              : }
      78              : 
      79            0 : path_t path_t::appendingSuffix(const path_t& suffix) const
      80              : {
      81            0 :     if (!suffix.m_path.empty() && suffix.m_path.front() == '.') {
      82            0 :         return m_path + suffix.m_path;
      83              :     }
      84              : 
      85            0 :     return m_path + '.' + suffix.m_path;
      86              : }
      87              : 
      88        12729 : String path_t::toString() const
      89              : {
      90        12729 :     return String::fromStdString(m_path);
      91              : }
      92              : 
      93        26940 : const std::string& path_t::toStdString() const
      94              : {
      95        26940 :     return m_path;
      96              : }
      97              : 
      98            1 : const char* path_t::c_str() const
      99              : {
     100            1 :     return m_path.c_str();
     101              : }
     102              : 
     103              : #ifndef NO_QT_SUPPORT
     104         2115 : path_t::path_t(const QString& s)
     105         2115 :     : m_path(s.toStdString())
     106              : {
     107         2115 : }
     108              : 
     109            4 : path_t::path_t(const QUrl& u)
     110            4 :     : m_path(u.toLocalFile().toStdString())
     111              : {
     112            4 : }
     113              : 
     114        32590 : QString path_t::toQString() const
     115              : {
     116        32590 :     return QString::fromStdString(m_path);
     117              : }
     118              : 
     119            0 : QUrl path_t::toQUrl() const
     120              : {
     121            0 :     return QUrl::fromLocalFile(QString::fromStdString(m_path));
     122              : }
     123              : 
     124            0 : std::wstring path_t::toStdWString() const
     125              : {
     126            0 :     return QString::fromStdString(m_path).toStdWString();
     127              : }
     128              : 
     129              : #endif
     130              : 
     131         4240 : std::string muse::io::suffix(const io::path_t& path)
     132              : {
     133         4240 :     return FileInfo::suffix(path).toLower().toStdString();
     134              : }
     135              : 
     136         1238 : io::path_t muse::io::filename(const io::path_t& path, bool includingExtension)
     137              : {
     138         1238 :     FileInfo fi(path);
     139         2476 :     return includingExtension ? fi.fileName() : fi.completeBaseName();
     140         1238 : }
     141              : 
     142           56 : io::path_t muse::io::basename(const io::path_t& path)
     143              : {
     144           56 :     FileInfo fi(path);
     145          112 :     return fi.baseName();
     146           56 : }
     147              : 
     148           98 : io::path_t muse::io::completeBasename(const io::path_t& path)
     149              : {
     150           98 :     FileInfo fi(path);
     151          196 :     return fi.completeBaseName();
     152           98 : }
     153              : 
     154            0 : io::path_t muse::io::absolutePath(const path_t& path)
     155              : {
     156            0 :     return FileInfo(path).absolutePath();
     157              : }
     158              : 
     159            2 : io::path_t muse::io::absoluteFilePath(const path_t& path)
     160              : {
     161            2 :     return FileInfo(path).absoluteFilePath();
     162              : }
     163              : 
     164          141 : io::path_t muse::io::dirpath(const io::path_t& path)
     165              : {
     166          141 :     return FileInfo(path).dir().path();
     167              : }
     168              : 
     169         1040 : io::path_t muse::io::absoluteDirpath(const io::path_t& path)
     170              : {
     171         1040 :     return FileInfo(path).dir().absolutePath();
     172              : }
     173              : 
     174            0 : bool muse::io::isAbsolute(const path_t& path)
     175              : {
     176            0 :     return FileInfo(path).isAbsolute();
     177              : }
     178              : 
     179           56 : bool muse::io::isAllowedFileName(const path_t& fn_)
     180              : {
     181           56 :     std::string fn = basename(fn_).toStdString();
     182           56 :     if (fn.empty()) {
     183            0 :         return false;
     184              :     }
     185              : 
     186              :     // Windows filenames are not case sensitive.
     187           56 :     fn = String::fromStdString(fn).toUpper().toStdString();
     188              : 
     189           56 :     static const std::string illegal="<>:\"|?*";
     190              : 
     191          469 :     for (const char& c : fn) {
     192              :         // Check for control characters
     193          414 :         if (c > 0 && c < 32) {
     194            1 :             return false;
     195              :         }
     196              : 
     197              :         // Check for illegal characters
     198         3307 :         for (const char& ilc : illegal) {
     199         2894 :             if (c == ilc) {
     200            1 :                 return false;
     201              :             }
     202              :         }
     203              :     }
     204              : 
     205              :     // Check for device names in filenames
     206              :     static const std::vector<std::string> devices = {
     207              :         "CON", "PRN",  "AUX",  "NUL",
     208              :         "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
     209              :         "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
     210           59 :     };
     211              : 
     212         1375 :     for (const std::string& s : devices) {
     213         1320 :         if (fn == s) {
     214            0 :             return false;
     215              :         }
     216              :     }
     217              : 
     218              :     // Check for trailing periods or spaces
     219           55 :     if (fn.back() == '.' || fn.back() == ' ') {
     220            0 :         return false;
     221              :     }
     222              : 
     223              :     // Check for pathnames that are too long
     224           55 :     if (fn.size() > 96) {
     225            0 :         return false;
     226              :     }
     227              : 
     228              :     // Since we are checking for a filename, it mustn't be a directory
     229           55 :     if (fn.back() == '\\') {
     230            0 :         return false;
     231              :     }
     232              : 
     233           55 :     return true;
     234           56 : }
     235              : 
     236            0 : io::path_t muse::io::escapeFileName(const io::path_t& fn_)
     237              : {
     238              :     //
     239              :     // special characters in filenames are a constant source
     240              :     // of trouble, this replaces some of them common in german:
     241              :     //
     242            0 :     String fn = fn_.toString();
     243            0 :     fn = fn.simplified();
     244            0 :     fn = fn.replace(' ',  '_');
     245            0 :     fn = fn.replace('\n', '_');
     246            0 :     fn = fn.replace(Char(0xe4), u"ae"); // &auml;
     247            0 :     fn = fn.replace(Char(0xf6), u"oe"); // &ouml;
     248            0 :     fn = fn.replace(Char(0xfc), u"ue"); // &uuml;
     249            0 :     fn = fn.replace(Char(0xdf), u"ss"); // &szlig;
     250            0 :     fn = fn.replace(Char(0xc4), u"Ae"); // &Auml;
     251            0 :     fn = fn.replace(Char(0xd6), u"Oe"); // &Ouml;
     252            0 :     fn = fn.replace(Char(0xdc), u"Ue"); // &Uuml;
     253            0 :     fn = fn.replace(Char(0x266d), u"b"); // musical flat sign, happen in instrument names, so can happen in part (file) names
     254            0 :     fn = fn.replace(Char(0x266f), u"#"); // musical sharp sign, can happen in titles, so can happen in score (file) names
     255              :     //FAT/NTFS special chars
     256            0 :     fn = fn.replace('<', '_')
     257            0 :          .replace('>', '_')
     258            0 :          .replace(':', '_')
     259            0 :          .replace('"', '_')
     260            0 :          .replace('/', '_')
     261            0 :          .replace('\\', '_')
     262            0 :          .replace('|', '_')
     263            0 :          .replace('?', '_')
     264            0 :          .replace('*', '_');
     265              : 
     266            0 :     return fn;
     267            0 : }
     268              : 
     269            0 : paths_t muse::io::pathsFromString(const std::string& str, const std::string& delim)
     270              : {
     271            0 :     if (str.empty()) {
     272            0 :         return {};
     273              :     }
     274              : 
     275            0 :     std::vector<std::string> strs;
     276            0 :     strings::split(str, strs, delim);
     277              : 
     278            0 :     paths_t ps;
     279            0 :     ps.reserve(strs.size());
     280            0 :     for (const std::string& s : strs) {
     281            0 :         ps.push_back(path_t(s));
     282              :     }
     283            0 :     return ps;
     284            0 : }
     285              : 
     286            0 : std::string muse::io::pathsToString(const paths_t& ps, const std::string& delim)
     287              : {
     288            0 :     std::string result;
     289            0 :     bool first = true;
     290            0 :     for (const path_t& _path: ps) {
     291            0 :         if (!first) {
     292            0 :             result += delim;
     293              :         }
     294            0 :         first = false;
     295            0 :         result += _path.toStdString();
     296              :     }
     297              : 
     298            0 :     return result;
     299            0 : }
     300              : 
     301            3 : path_t muse::io::toNativeSeparators(const path_t& path)
     302              : {
     303              : #ifndef NO_QT_SUPPORT
     304            3 :     return QDir::toNativeSeparators(path.toQString());
     305              : #else
     306              :     return path;
     307              : #endif
     308              : }
        

Generated by: LCOV version 2.0-1