1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the Qt Linguist of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "ioutils.h"
43
44#include <QtCore/QDir>
45#include <QtCore/QFile>
46
47#ifdef Q_OS_WIN
48# include <windows.h>
49#else
50# include <sys/types.h>
51# include <sys/stat.h>
52# include <unistd.h>
53#endif
54
55using namespace ProFileEvaluatorInternal;
56
57IoUtils::FileType IoUtils::fileType(const QString &fileName)
58{
59 Q_ASSERT(fileName.isEmpty() || isAbsolutePath(fileName));
60#ifdef Q_OS_WIN
61 DWORD attr = GetFileAttributesW((WCHAR*)fileName.utf16());
62 if (attr == INVALID_FILE_ATTRIBUTES)
63 return FileNotFound;
64 return (attr & FILE_ATTRIBUTE_DIRECTORY) ? FileIsDir : FileIsRegular;
65#else
66 struct ::stat st;
67 if (::stat(fileName.toLocal8Bit().constData(), &st))
68 return FileNotFound;
69 return S_ISDIR(st.st_mode) ? FileIsDir : FileIsRegular;
70#endif
71}
72
73bool IoUtils::isRelativePath(const QString &path)
74{
75 if (path.startsWith(QLatin1Char('/')))
76 return false;
77#ifdef Q_OS_WIN
78 if (path.startsWith(QLatin1Char('\\')))
79 return false;
80 // Unlike QFileInfo, this won't accept a relative path with a drive letter.
81 // Such paths result in a royal mess anyway ...
82 if (path.length() >= 3 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter()
83 && (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\')))
84 return false;
85#endif
86 return true;
87}
88
89QStringRef IoUtils::fileName(const QString &fileName)
90{
91 return fileName.midRef(fileName.lastIndexOf(QLatin1Char('/')) + 1);
92}
93
94QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName)
95{
96 if (fileName.isEmpty())
97 return QString();
98 if (isAbsolutePath(fileName))
99 return QDir::cleanPath(fileName);
100 return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName);
101}
102
103#ifdef QT_BOOTSTRAPPED
104inline static bool isSpecialChar(ushort c)
105{
106 // Chars that should be quoted (TM). This includes:
107#ifdef Q_OS_WIN
108 // - control chars & space
109 // - the shell meta chars "&()<>^|
110 // - the potential separators ,;=
111 static const uchar iqm[] = {
112 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
113 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
114 };
115#else
116 static const uchar iqm[] = {
117 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
118 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
119 }; // 0-32 \'"$`<>|;&(){}*?#!~[]
120#endif
121
122 return (c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)));
123}
124
125inline static bool hasSpecialChars(const QString &arg)
126{
127 for (int x = arg.length() - 1; x >= 0; --x)
128 if (isSpecialChar(arg.unicode()[x].unicode()))
129 return true;
130 return false;
131}
132
133QString IoUtils::shellQuote(const QString &arg)
134{
135 if (!arg.length())
136 return QString::fromLatin1("\"\"");
137
138 QString ret(arg);
139 if (hasSpecialChars(ret)) {
140#ifdef Q_OS_WIN
141 // Quotes are escaped and their preceding backslashes are doubled.
142 // It's impossible to escape anything inside a quoted string on cmd
143 // level, so the outer quoting must be "suspended".
144 ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\""));
145 // The argument must not end with a \ since this would be interpreted
146 // as escaping the quote -- rather put the \ behind the quote: e.g.
147 // rather use "foo"\ than "foo\"
148 int i = ret.length();
149 while (i > 0 && ret.at(i - 1) == QLatin1Char('\\'))
150 --i;
151 ret.insert(i, QLatin1Char('"'));
152 ret.prepend(QLatin1Char('"'));
153#else // Q_OS_WIN
154 ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
155 ret.prepend(QLatin1Char('\''));
156 ret.append(QLatin1Char('\''));
157#endif // Q_OS_WIN
158 }
159 return ret;
160}
161#endif
162